Skip to main content
Glama

lsl-mcp

A Model Context Protocol (MCP) server providing accurate LSL (Linden Scripting Language) reference data to AI coding assistants. Grounded in the official Second Life wiki, with a curated database of AI-specific pitfalls.

Motivation

AI coding assistants (Claude Code, Kiro, etc.) frequently produce incorrect LSL — hallucinated function names, unsupported syntax, and wrong signatures. This server gives those tools a live, authoritative reference to query against rather than relying on training data.

Related MCP server: PAELLADOC

Design Goals

  • Portable LSL only — no Firestorm-specific syntax

  • AI-aware — pitfalls are categorised and tagged by which tool produced them

  • Git-tracked — JSON is the source of truth; SQLite is always derivable

  • Incrementally maintainable — new pitfalls are captured via CLI as they are discovered


Project Structure

lsl-mcp/
├── server.py              # MCP server entrypoint
├── db/
│   ├── schema.sql         # Table definitions
│   └── lsl.db             # SQLite database (gitignored)
├── data/
│   ├── functions/         # One JSON file per LSL function (source of truth)
│   ├── pitfalls.json      # Language pitfalls collection (source of truth)
│   └── constants.json     # LSL constants
├── scripts/
│   ├── scrape_wiki.py     # Populates data/functions/ from the LSL wiki
│   ├── load_db.py         # Imports JSON data into lsl.db
│   └── add_pitfall.py     # CLI tool for adding new pitfalls
├── tools/
│   ├── lookup.py          # lsl_lookup_function, lsl_search
│   ├── pitfalls.py        # lsl_get_pitfalls, lsl_check_code
│   └── reference.py       # lsl_list_events, lsl_constants
└── pyproject.toml

Requirements

  • Python 3.11+

  • uv (recommended) or pip


Initial Setup

1. Install dependencies

Using uv (recommended):

uv sync

Using pip:

pip install -e .

For development (includes pytest):

uv sync --dev
# or
pip install -e ".[dev]"

2. Scrape the LSL wiki

Populates data/functions/ with one JSON file per function. Approximately 700 functions; takes several minutes due to polite request throttling.

python scripts/scrape_wiki.py

Test a single function first:

python scripts/scrape_wiki.py --function llListen --dry-run

2. Initialise the database

Creates db/lsl.db from db/schema.sql and loads all JSON data.

python scripts/load_db.py

3. Connect to Claude Code

Register the server with Claude Code (personal scope):

# using uv (recommended)
claude mcp add --transport stdio lsl -- uv run /path/to/lsl-mcp/server.py

# using python directly
claude mcp add --transport stdio lsl -- python /path/to/lsl-mcp/server.py

Or add a .mcp.json to your project root for project-wide sharing:

{
  "mcpServers": {
    "lsl": {
      "type": "stdio",
      "command": "uv",
      "args": ["run", "/path/to/lsl-mcp/server.py"]
    }
  }
}

Verify the server is connected:

claude mcp list

MCP Tools

Tool

Description

lookup_function(name)

Exact or fuzzy match on function name. Returns full record including signature, parameters, caveats, and known AI pitfalls. Falls back to did_you_mean on miss.

search_functions(query, limit?)

Full-text search across function names and descriptions. Returns ranked summary list.

get_pitfalls(category?, ai_source?)

Returns all pitfall entries, optionally filtered by category or source tool.

check_code(code)

Scans raw LSL source for known AI-generated mistakes. Returns line numbers and suggestions.

list_events(name?)

Returns all valid LSL event signatures, or looks up one by name.

get_constants(category?, name?)

Returns constants by category or direct name lookup.

Before starting an LSL task:
    get_pitfalls()               ← full briefing on known mistakes

While writing LSL:
    lookup_function("llFoo")     ← verify signature before use
    list_events("touch_start")   ← verify event name and parameters
    get_constants("permissions")  ← browse constants by category

Before presenting code to the user:
    check_code(generated_lsl)    ← catch mistakes before they reach the user

Pitfall Categories

Category

Description

reserved_words

LSL type names or keywords used as variable identifiers

nonexistent_functions

Hallucinated function names with no LSL equivalent

unsupported_syntax

Syntax valid in other languages but a compile error in LSL

scoping

Permission/access scope issues that silently block operations

type_coercion

Implicit casting that LSL does not perform

state_behavior

Unexpected behavior around state changes

performance

Functions with hidden sleeps or inefficient patterns


Adding a Pitfall

When an AI tool produces incorrect LSL, capture it:

python scripts/add_pitfall.py \
  --category nonexistent_functions \
  --title "llStringReplace does not exist in LSL" \
  --bad "llStringReplace(src, old, new)" \
  --good "llReplaceSubString(src, pattern, replacement, count)" \
  --ai-source kiro \
  --notes "llStringReplace is a plausible-sounding hallucination, likely confused with string replace conventions in other languages."

Then sync the database and commit:

python scripts/load_db.py --only pitfalls
git add data/pitfalls.json
git commit -m "pitfall(func_001): llStringReplace does not exist [kiro]"

Claude-assisted capture

Describe the mistake to Claude in plain language. Claude will format it into the correct schema and emit the exact CLI command to run. You verify, run it, and commit. Claude never writes to the database directly — the CLI is the deterministic protocol.

--dry-run

Preview what would be written without touching any files:

python scripts/add_pitfall.py --category unsupported_syntax --title "..." --dry-run

Refreshing Wiki Data

Re-scrape all functions and reload:

python scripts/scrape_wiki.py --overwrite
python scripts/load_db.py --only functions

Re-scrape a single function:

python scripts/scrape_wiki.py --function llReplaceSubString
python scripts/load_db.py --only functions

Database

db/lsl.db is gitignored — it is always fully derivable from the JSON sources via load_db.py. Only data/ and db/schema.sql are version-controlled.

To rebuild from scratch:

python scripts/load_db.py --reset

Pitfall ID Format

IDs are assigned automatically by add_pitfall.py based on category:

Category

Prefix

Example

reserved_words

lang

lang_001

nonexistent_functions

func

func_001

unsupported_syntax

syn

syn_001

scoping

scope

scope_001

type_coercion

type

type_001

state_behavior

state

state_001

performance

perf

perf_001


Known Pitfalls

ID

Category

Issue

Source

type_001

type_coercion

Boolean NOT ! does not work on strings

claude-code

state_001

state_behavior

Cached owner key not updated after ownership transfer

claude-code

lang_001

reserved_words

key used as variable name

kiro

func_001

nonexistent_functions

llStringReplace does not exist

kiro

syn_001

unsupported_syntax

Ternary operator not supported

both

syn_002

unsupported_syntax

Switch statements not supported

both

scope_001

scoping

Transfer-only permissions silently prevent script edits

kiro

perf_001

state_behavior

llSetPrimitiveParams has forced 0.2s sleep; use llSetLinkPrimitiveParamsFast

both


Testing

# Run all tests
python3 -m pytest

# Verbose output
python3 -m pytest -v

# Single module
python3 -m pytest tests/test_pitfalls.py

Tests use an in-memory SQLite fixture database built from db/schema.sql — no real lsl.db or network access required. The conftest.py fixture patches DB_PATH in all tool modules automatically.

Test file

Coverage

test_lookup.py

lsl_lookup_function, lsl_search

test_pitfalls.py

lsl_get_pitfalls, lsl_check_code

test_reference.py

lsl_list_events, lsl_constants

test_add_pitfall.py

ID generation logic in add_pitfall.py


gitignore

db/lsl.db
data/functions/
data/scrape_errors.json
__pycache__/
*.pyc
.venv/

data/functions/ is gitignored because it is fully regenerable from the wiki. Only data/pitfalls.json and data/constants.json are committed — these contain hand-curated data that cannot be scraped.

Available Tools

6 tools
check_codeA

Scan an LSL code snippet for known AI-generated pitfalls.

Checks for nonexistent function calls, unsupported syntax (ternary operators, switch statements), reserved words used as variable names, and other patterns from the pitfalls database.

Call this on any LSL you generate before presenting it to the user. Returns line numbers and suggestions for each issue found.

Args: code: Raw LSL source code as a string.

Inputs: code (required).

get_constantsA

Return LSL constants, optionally filtered by category or name.

Call with no arguments to see available categories and total count. Use category to browse a group (e.g. "permissions", "prim_params"). Use name for a direct lookup (e.g. "NULL_KEY", "PERMISSION_TAKE_CONTROLS").

Args: category: Optional category filter. See response for valid categories. name: Optional exact constant name. Takes precedence over category.

Inputs: category, name.

get_pitfallsA

Return known LSL pitfalls for AI coding assistants.

Call with no arguments for a full briefing before starting an LSL task. Filter by category or by which AI tool produced the mistake.

Args: category: reserved_words | nonexistent_functions | unsupported_syntax | scoping | type_coercion | state_behavior ai_source: kiro | claude-code | both

Inputs: category, ai_source.

list_eventsA

Return valid LSL event signatures.

Call with no arguments to get all events and verify an event name exists. Call with a name to get the full signature and parameter details.

Args: name: Optional event name, e.g. "listen" or "touch_start". Omit to return all events.

Inputs: name.

lookup_functionA

Look up an LSL function by name.

Returns the full function record: signature, parameters, return type, delay, energy cost, caveats, examples, related functions, and any known AI-specific pitfalls associated with this function.

Falls back to fuzzy matching if the exact name is not found, and returns a 'did_you_mean' list when no match exists at all — helping catch hallucinated function names.

Args: name: Function name, e.g. "llListen" or "llReplaceSubString".

Inputs: name (required).

search_functionsA

Full-text search across LSL function names and descriptions.

Use when you know roughly what a function does but not its exact name. Returns a ranked summary list — call lookup_function for the full record.

Args: query: Keywords or natural language, e.g. "listen channel message" or "set prim texture face". limit: Maximum results to return (default 10, max 25).

Inputs: query (required), limit.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4.6/5.0

    Scored across 6 tools

    Disambiguation5/5

    Each tool targets a distinct aspect of LSL development: code checking, constants, pitfalls database, events, function lookup by name, and full-text search. No two tools have overlapping purposes, and descriptions clearly differentiate them.

    Naming Consistency5/5

    All tool names follow a consistent verb_noun pattern in lowercase snake_case (e.g., check_code, lookup_function). The naming is predictable and easy to understand.

    Tool Count5/5

    With 6 tools, the server is well-scoped for assisting with LSL code. Each tool provides essential functionality without unnecessary bloat. The count feels appropriate for the domain.

    Completeness5/5

    The tool set covers the core needs for LSL development: checking for pitfalls, exploring constants, events, and functions. Missing features like syntax guidance are mitigated by detailed returns from lookup_function and search_functions.

    Maintenance

    ActivityInactive
    ResponsivenessLimited data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      F
      maintenance
      A Model Context Protocol (MCP) server that implements AI-First Development framework principles, allowing LLMs to interact with context-first documentation tools and workflows for preserving knowledge and intent alongside code.
      336
      AGPL 3.0
    • F
      license
      Not graded
      quality
      D
      maintenance
      A Model Context Protocol server that provides AI models with structured access to external data and services, acting as a bridge between AI assistants and applications, databases, and APIs in a standardized, secure way.
      2
      -
    • A
      license
      B
      quality
      D
      maintenance
      Production-grade, autonomous Model Context Protocol (MCP) server that elevates AI models from stateless code generators into persistent, self-verifying software engineers.
      21
      1
      MIT