跳到正文
GitHub·· 9 天前AI 评分36

Scriptling:面向 Go 的类 Python 沙箱脚本语言,支持 MCP 与 LLM 智能体

paularlott/scriptling

AI 导读

paularlott/scriptling 是一款面向 Go 的类 Python 沙箱解释器,专为 LLM 智能体执行代码和调用 REST API 设计,支持 MCP 集成。

正文

Scriptling

GitHub License

Scriptling - Python-like Scripting Language for Go

A minimal, sandboxed interpreter for LLM agents to execute code and interact with REST APIs. Python-inspired syntax designed for embedding in Go applications.

Features

  • Python-like syntax with indentation-based blocks
  • Core types: integers, floats, strings, booleans, lists, dictionaries
  • Control flow: if/elif/else, while, for loops, break, continue
  • Object-oriented: Classes with single inheritance, methods, and constructors
  • Advanced features: functions, lambda, list comprehensions, error handling
  • Libraries: including json, regex, math, time, requests, subprocess (load on demand)
  • Databases: SQLite, MySQL/MariaDB, PostgreSQL, Valkey/Redis and BadgerDB plugins with a shared API and a script-side ORM (query builders, model gateways)
  • Plugins: extend with Go, C, PHP or any language speaking JSON-RPC, loaded from disk or http(s)
  • Go integration: Register functions, exchange variables
  • Fast: Lightweight interpreter, only loads what you need
  • Sandboxed: No filesystem or network access unless enabled via libraries
  • MCP support: Model Context Protocol for LLM integration
  • CLI tool: Run scripts, start HTTP server with MCP support
  • Script metadata: Scripts declare their requirements — scriptling version, libraries, plugins — in a PEP 723-style # /// script block, checked before they run
  • Extensible: Create custom functions, libraries, and classes in Go or Scriptling
  • Linter: Built-in linter for syntax checks
  • OpenAPI support: Generate Scriptling client libraries from OpenAPI specs with o2s tool

Differences from Python

While Scriptling is inspired by Python, it has some key differences:

  • Single Inheritance Only: Classes support single inheritance (e.g., class Dog(Animal):), but not multiple inheritance.
  • No async/await or yield generators.
  • Simplified Scope: nonlocal and global keywords work slightly differently.
  • Eager lazy import: PEP 810 lazy import x / lazy from x import y is accepted, but the hint is ignored and the module is imported immediately.
  • Go Integration: Designed primarily for embedding in Go, with direct type mapping.
  • Sandboxed: No direct access to filesystem or network unless explicitly enabled via libraries.

Installation

CLI

brew install paularlott/tap/scriptling

The sqlite, sql, valkey and badgerdb database plugins are compiled in.

Prefer a leaner binary without them? scriptling-slim installs the same CLI with no database drivers — load them at runtime with the scriptling-plugins formula instead:

brew install paularlott/tap/scriptling-slim
brew install paularlott/tap/scriptling-plugins
export SCRIPTLING_PLUGIN_DIR="$(brew --prefix)/opt/scriptling-plugins/libexec/plugins"
# or pass per run: scriptling --plugin-dir "$(brew --prefix)/opt/scriptling-plugins/libexec/plugins" script.py

Release zips and plugin binaries are on the releases page — every zip (default and slim alike) contains the binary named plainly scriptling, and the plugins zip for your platform (plugins-linux-arm64.zip and friends) contains all four binaries named plainly (sqlite, sql, valkey, badgerdb). Unzip it and point --plugin-dir at the folder, or set SCRIPTLING_PLUGIN_DIR.

Go Library

go get github.com/paularlott/scriptling

Quick Start

package main

import (
    "fmt"
    "github.com/paularlott/scriptling"
    "github.com/paularlott/scriptling/stdlib"
)

func main() {
    // Create interpreter
    p := scriptling.New()

    // Register all standard libraries
    stdlib.RegisterAll(p)

    // Execute Scriptling code
    result, err := p.Eval(`
# Variables and types
x = 42
name = "Alice"
numbers = [1, 2, 3]

# Functions
def greet(n):
    return "Hello " + n

# Output
print(greet(name))
print("Sum:", x + len(numbers))
`)
    if err != nil {
        fmt.Println("Error:", err)
    }
}

CLI Tool

Scriptling includes a command-line interface for running scripts directly:

# Install Task (build tool)
brew install go-task/tap/go-task

# Build CLI for current platform
task build

# Run scripts
./bin/scriptling script.py
echo 'print("Hello")' | ./bin/scriptling
./bin/scriptling --interactive

# Build for all platforms
task build-all

HTTP, MCP, and JSON-RPC Server

The CLI can also run as an HTTP server with MCP (Model Context Protocol) and JSON-RPC support:

# Start HTTP server on port 8000
./bin/scriptling --server :8000 script.py

# With MCP tools for LLM integration
./bin/scriptling --server :8000 --mcp-tools ./tools script.py

# With JSON-RPC over HTTP at /json-rpc
./bin/scriptling --server :8000 --json-rpc script.py

# MCP and JSON-RPC can run side by side
./bin/scriptling --server :8000 --mcp-tools ./tools --json-rpc script.py

# With TLS and authentication
./bin/scriptling --server :8443 --tls-generate --bearer-token secret script.py

See scriptling-cli/README.md for details.

Go API

Basic Usage

import (
    "github.com/paularlott/scriptling"
    "github.com/paularlott/scriptling/libloader"
    "github.com/paularlott/scriptling/stdlib"
)

p := scriptling.New()

// Register libraries as needed
stdlib.RegisterAll(p)  // Register all standard libraries
// Or register individual libraries:
// p.RegisterLibrary(stdlib.JSONLibraryName, stdlib.JSONLibrary)
// p.RegisterLibrary(stdlib.MathLibraryName, stdlib.MathLibrary)

// Execute code
result, err := p.Eval("x = 5 + 3")

// Exchange variables
p.SetVar("name", "Alice")
value, objErr := p.GetVarAsString("name")

// Register Go functions
p.RegisterFunc("custom", func(ctx context.Context, kwargs map[string]object.Object, args ...object.Object) object.Object {
    return object.NewString("result")
})

// Register Scriptling functions
p.RegisterScriptFunc("my_func", `
def my_func(x):
    return x * 2
my_func
`)

// Register Scriptling libraries
p.RegisterScriptLibrary("mylib", `
def add(a, b):
    return a + b
PI = 3.14159
`)

// Set up library loader for dynamic loading from filesystem
// Supports Python-style folder structure: libs/knot/groups.py → import knot.groups
loader := libloader.NewFilesystem("/app/libs")
p.SetLibraryLoader(loader)

Libraries

import (
    "github.com/paularlott/scriptling"
    "github.com/paularlott/scriptling/stdlib"
    "github.com/paularlott/scriptling/extlibs"
)

// Create interpreter
p := scriptling.New()

// Register all standard libraries
stdlib.RegisterAll(p)

// Or register individual standard libraries
p.RegisterLibrary(stdlib.JSONLibrary)
p.RegisterLibrary(stdlib.MathLibrary)

// Register additional custom libraries
p.RegisterLibrary(extlibs.RequestsLibrary)

// Register os and pathlib with security restrictions
extlibs.RegisterOSLibrary(p, []string{"/tmp", "/home/user/data"})
extlibs.RegisterPathlibLibrary(p, []string{"/tmp", "/home/user/data"})

// Import libraries programmatically (no need for import statements in scripts)
p.Import("json")

// Use in scripts
p.Eval(`
import requests
import os

response = requests.get("https://api.example.com/data")
data = json.parse(response["body"])  # json already imported via p.Import()
files = os.listdir("/tmp")
`)

Examples

See examples/ directory:

  • scripts/ - Script examples and Go integration
  • openai/scriptlingcoder/ - AI coding assistant with custom tools (inspired by nanocode)
  • mcp-tools/ - MCP tools for use with CLI MCP server

Run examples:

cd examples/scripts
go run main.go test_basics.py

# AI coding assistant (⚠️ executes AI-generated code)
cd examples/openai/scriptlingcoder
../../../bin/scriptling scriptlingcoder.py

Tools

  • o2s - OpenAPI to Scriptling converter. Generate HTTP client libraries from OpenAPI v3 specs

Documentation

Full documentation is available at scriptling.dev

Testing

# Run all tests
go test ./...

# Run benchmarks
go test -bench=. -run=Benchmark

License

MIT

Contributing

Contributions are welcome! See CONTRIBUTING.md for guidelines.

来源:GitHub · github.com