Future tools for the daslang MCP server, organized by priority and difficulty.
| Tool | Description |
|---|---|
compile_check |
Compile file(s), return errors or success. Supports single file, comma-separated list, or glob pattern |
list_functions |
List all functions after macro expansion |
list_types |
List structs, classes, enums, type aliases |
list_requires |
List direct and transitive require dependencies |
list_modules |
List all available modules (builtin + daslib) |
list_module_api |
List functions, types, enums, globals, and annotations exported by a module (shows parent types for structs and handled types) |
find_symbol |
Cross-module symbol search by substring (functions, generics, structs, handled types, enums, globals, typedefs/aliases) |
ast_dump |
Dump AST of expression or function (S-expression or source mode). Optional lineinfo for source locations and atEnclosure |
program_log |
Full post-compilation program text (like options log) with optional function filter |
run_script |
Run inline code or a .das file, capture stdout |
run_test |
Run dastest on a test file |
format_file |
Format a .das file in place |
convert_to_gen2 |
Convert gen1 (indentation) syntax to gen2 (braces/parens) |
goto_definition |
Resolve symbol at cursor to its definition (variable, function, field, struct, enum, typedef, builtin). Optional no_opt |
type_of |
Return resolved type of expression at cursor position. Optional no_opt |
find_references |
Find all references to symbol at cursor (calls, variables, fields, type refs, addr, enum/bitfield values, aliases, global declarations). Scope: file or all. Optional no_opt |
eval_expression |
Evaluate a daslang expression and return printed result. Supports comma-separated module imports via require parameter |
describe_type |
Describe a type's fields, methods, values, and base type. Supports structs, classes, handled types, enums, bitfields, variants, tuples, typedefs |
grep_usage |
Parse-aware symbol search across .das files using ast-grep + tree-sitter. Conditional on sg CLI being installed |
outline |
List all declarations (functions, structs, classes, enums, globals, typedefs) in a file or set of files using tree-sitter. No compilation needed. Conditional on sg CLI |
.das_projectsupport — all file-based tools accept an optionalprojectparameter pointing to a.das_projectfile for custom module resolution and sandboxing- Request logging — file-based logging with timestamps for debugging
- Unified file utilities —
resolve_path()andmake_relative_path()live intools/common.das;expand_glob()andparse_file_list()were promoted todaslib/fioso any CLI tool can use them, not just MCP. Glob patterns:*/?/**/[abc]/[!abc]. (!patterngitignore-style exclusion is not implemented; useglob_filteredwith explicit excludes)
goto_definition, type_of, and find_references use daslib/ast_cursor (find_at_cursor) to map file+line+column to AST nodes. They support:
- Functions:
ExprCall(calls),ExprAddr(function pointers@@func) - Variables:
ExprVar(local and global), including declaration-based lookup viafor_each_global - Fields:
ExprField,ExprSafeField(.field,?.field) - Enums:
ExprConstEnumeration(enum values likeColor.Red) - Bitfields:
ExprConstBitfield(bitfield values likeFlags.readable) - Aliases:
TypeDecl.alias— coverstypedef,bitfield,variant,tupledeclarations - Structs/Classes: type references via
TypeDecl.structType - Builtins: built-in function signatures (no source location)
The no_opt parameter disables compiler optimizations (CodeOfPolicies.no_optimizations), preserving ExprVar nodes for globals and ExprConstBitfield/ExprConstEnumeration nodes that would otherwise be constant-folded away.
find_references also supports declaration-based lookup: cursor on def funcName, struct Name, enum Name, bitfield Name, variant Name, tuple Name, or let globalVar declarations identifies the target via for_each_function/for_each_structure/for_each_enumeration/for_each_typedef/for_each_global.
Implemented as a standalone tool. Searches all modules for a type by name and describes its fields, methods, values, base type. Supports structs, classes, handled types, enums, bitfields, variants, tuples, and typedefs. Optional module parameter to limit search scope.
Implemented using ast-grep + tree-sitter for parse-aware identifier search. Finds symbol occurrences excluding comments and strings — no compilation needed. Conditionally available when sg (ast-grep) CLI is installed. Server prints install instructions if missing.
Parameters: symbol (required), directory (optional), glob (optional file filter), context_lines (optional). Output grouped by file with line numbers.
Merged into compile_check — supports comma-separated file lists and glob patterns (e.g., utils/mcp/tools/*.das). Reports per-file pass/fail with summary.
Merged into list_module_api as the annotations section. Lists function annotations, structure annotations, call macros, reader macros, variant macros, typeinfo macros, for-loop macros, and type macros.
Evaluates a daslang expression via let _res_ = <expr>; print("{_res_}\n") scaffold. Supports comma-separated require parameter for module imports. Works with typeinfo, complex expressions, and library functions.
What: Rename a function, variable, struct, field, or enum value across one or more files.
Why: Safe mechanical renaming is tedious and error-prone by hand. The compiler knows all references.
Implementation approach:
- First, use
goto_definitionto find the definition. - Then, use
find_referencesto find all usages. - Apply text replacements at each location.
- Re-compile to verify the rename didn't break anything.
- Return the list of modified files and a diff.
Important constraints:
- Must handle qualified names: renaming struct
Foomust also renameFoo.fieldaccess,new Foo(), type annotationsx : Foo, etc. - Method renames:
obj.method()andobj |> method()andobj->method()all need updating. - Must NOT rename unrelated symbols that happen to share the same name (different module, different scope).
- Should refuse to rename builtins (no source to modify).
Parameters:
file(required) — file containing the symbol definitionsymbol(required) — current namenew_name(required) — desired new namescope(optional) —"file"or"project"dry_run(optional, default true) — if true, return diff without modifying files
Output: List of changes (file, line, old_text, new_text) and compilation check result.
Difficulty: Hard. Depends on goto_definition and find_references. Safe renaming across files is complex.
What: Extract a selected range of code into a new function, automatically determining parameters and return values.
Why: Common refactoring. The AI can identify the code to extract but needs compiler help to determine which variables must become parameters.
Implementation approach:
- Parse the selected code range to identify:
- Variables read but not defined in the selection → become function parameters
- Variables defined in the selection and used after it → become return values
- Variables defined and only used within the selection → stay local
- Generate the function signature with proper types (from the compiled AST).
- Replace the selected code with a call to the new function.
- Handle
var(mutable) parameters correctly — if the selection modifies a variable used later, it needsvarparameter.
Challenges:
- daslang's move semantics: if the selection moves a value (
<-), the extraction must preserve that. - Block/lambda captures: if extracting code that's inside a block, the new function might need different parameter passing.
- Control flow:
return,break,continueinside the selection complicate extraction.
Parameters:
file(required) — source filestart_line(required) — first line of selectionend_line(required) — last line of selectionfunction_name(required) — name for the new functiondry_run(optional, default true)
Output: The new function definition, the modified call site, and a compilation check.
Difficulty: Very hard. Requires deep AST analysis of data flow. Could start with a simpler version that only handles straightforward cases (no control flow escapes, no moves).
What: Replace a function call with the function's body, substituting parameters.
Why: The inverse of extract — useful for removing unnecessary abstraction.
Difficulty: Hard. Needs parameter substitution, handling of return statements, variable name conflicts.
What: Given a compiler error message, provide a detailed explanation with fix suggestions.
Why: daslang error messages can be cryptic, especially for type mismatches, move semantics, and macro expansion errors. The AI can provide better explanations but needs structured error info.
Implementation approach:
- Parse the error output from
compile_checkinto structured fields: error code, file, line, message, context. - Match against known error patterns and provide:
- Plain-English explanation
- Common causes
- Suggested fixes with code snippets
- Could maintain a knowledge base of error patterns (similar to Rust's error index).
Parameters:
file(required) — file with the errorerror_text(optional) — specific error message to explain (if not provided, compile and explain all errors)
Output: Structured explanation per error: what it means, why it happens, how to fix it.
Difficulty: Medium. Pattern matching on error messages is straightforward. Quality depends on the knowledge base.
What: Search for functions by their type signature (like Haskell's Hoogle or Gleam's Gloogle).
Why: "I have a string and want an int — what function does that?" This is incredibly useful for discovering API.
Implementation approach:
- Index all functions across registered modules by parameter types and return type.
- Parse a query like
string -> intor(array<int>, int) -> bool. - Match functions where parameter/return types are compatible (exact match, then subtype match).
- Rank by relevance: exact matches first, then partial matches.
Parameters:
query(required) — type signature query (e.g.,string -> int,float, float -> float)module(optional) — limit search to a specific module
Output: List of matching functions with their full signatures and module names.
Difficulty: Medium-hard. Parsing type queries and matching against TypeDecl requires a type compatibility checker.
What: Given a file with compilation errors, attempt automatic fixes and return the corrected code.
Why: Many errors have mechanical fixes: missing var, wrong type cast, missing require, missing parentheses.
Implementation approach:
- Compile the file, collect errors.
- For each error, apply pattern-matched fixes:
- "expecting T, got U" → insert cast or conversion
- "undefined symbol X" → add
requirefor the module containing X (usingfind_symbol) - "variable not found" → suggest
vardeclaration - "can't copy" → suggest
:=or<-
- Re-compile after each fix to verify it works.
- Iterate until no more auto-fixable errors remain.
Parameters:
file(required) — file to fixdry_run(optional, default true)max_iterations(optional, default 5)
Output: Diff of changes made, remaining errors (if any), compilation result.
Difficulty: Hard. Each error pattern needs a specific fixer. Interactions between fixes can cause cascading issues.
What: Build an in-memory index of all .das files in a project directory for fast cross-file operations.
Why: Many tools (find_references, rename_symbol) need to know about all files in a project. Compiling each file on every query is too slow.
Implementation approach:
- Scan a directory tree for
.dasfiles. - Compile each file and cache: function/type/global definitions, require graph, symbol locations.
- Invalidate cache entries when files change (check mtime).
- Other tools query the index instead of compiling from scratch.
Difficulty: Hard. Cache invalidation is the main challenge (macro expansion means a change in one file can affect others).
What: Visualize the full dependency graph of a file or project.
Why: Understanding module dependencies helps with architecture decisions, finding circular deps, and planning refactors.
Implementation approach:
- Already have
list_requiresfor single-file deps. Extend to:- Build a graph across all files in a project
- Detect cycles
- Output in DOT format or structured JSON
- Show which deps are direct vs transitive
Parameters:
fileorroot— starting pointformat—"text","json", or"dot"depth(optional) — max depth to traverse
Difficulty: Medium. Building on list_requires infrastructure.
What: Search a package registry for daslang packages by name, description, or functionality.
Status: Deferred — waiting for the daslang package manager to be implemented.
What: Generate boilerplate code for common patterns: new module, test file, C++ binding, etc.
Why: Ensures generated code follows project conventions (correct options, requires, annotations).
Templates:
module— new daslib module with proper headertest— test file with[test]functions and fixture setupbinding— C++ module binding skeleton (.das_module+ C++ stub)tutorial— tutorial .das file with comments
Difficulty: Easy-medium. Template-based generation. The AI already does this well, so the value-add is mainly in ensuring conventions.
Recommended order based on value/effort ratio:
goto_definition✅ Implementedtype_of✅ Implementedfind_references✅ Implemented (file + all-modules scope, declaration lookup)program_log✅ Implemented (full program text, optional function filter)ast_dump with LineInfo✅ Implemented (lineinfoparameter, showsatEnclosure)dot-call LineInfo fix✅ Fixed (atEnclosureon dot-call/arrow-call expressions in parser + inference).das_project support✅ Implemented (per-toolprojectparameter)describe_type✅ Implemented (fields, methods, values, base types for all type kinds)grep_usage✅ Implemented (ast-grep + tree-sitter, conditional onsgCLI) 9b.outline✅ Implemented (tree-sitter kind-based rules, conditional onsgCLI)batch_compile✅ Implemented (merged intocompile_checkwith comma-separated and glob support)list_annotations✅ Implemented (merged intolist_module_apiasannotationssection)eval_expression✅ Implemented (expression eval withrequiresupport)- explain_error — high value, relatively easy
- dependency_graph — medium value, easy (extends
list_requires) - type_search — high value for API discovery, medium-hard effort
- rename_symbol — high value, depends on goto_definition + find_references (both done)
- try_fix — medium-high value, hard
- extract_function — medium value, very hard
- workspace_index — enabler for cross-file tools at scale
- scaffold — low priority (AI already generates good code)
- package_search — deferred until package manager exists
Cursor-based tools (goto_definition, type_of, find_references) use daslib/ast_cursor module:
find_at_cursor(program, file, line, col)returns an array ofCursorHitfrom innermost to outermost expression- Each
CursorHithas:expr(the expression),func(enclosing function),rtti(node type name),name(symbol name if applicable) compile_program(file, export_all, no_opt, project)intools/common.daswraps compilation with proper CodeOfPolicies
For project-level tools, we need to compile multiple files. Options:
- Sequential: compile each file independently. Simple but slow.
- Cached: maintain a
ModuleGroupacross compilations. Faster but complex lifetime management. - Indexed: pre-scan files for
requirestatements (text-level), build dependency order, compile in order. Best for large projects.
Many complex tools are compositions of simpler ones:
rename_symbol=goto_definition+find_references+ text replacement +compile_checktry_fix=compile_check+ error pattern matching + text edit +compile_checkextract_function= AST analysis + code generation +compile_check
Building the foundational tools well creates a platform for everything else.