Skip to content
Back to skills

Lsp Extract Function

ASecurity

Extract a selected code block into a named function. Primary path uses the language server's extract-function code action; falls back to manual extraction when no code action is available. Validates captured variables, scope shadowing, and compilation after extraction.

  • 156 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added June 5, 2026
developmentjavascripttypescriptpythongojavagit

Works with

  • mcp

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned June 5, 2026

npx -y skills add blackwell-systems/agent-lsp --skill lsp-extract-function --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Lsp Extract Function?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Lsp Extract Function
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/blackwell-systems-lsp-extract-function/badge)](https://www.skillsdirectory.com/skills/blackwell-systems-lsp-extract-function)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: lsp-extract-function
description: Extract a selected code block into a named function. Primary path uses the language server's extract-function code action; falls back to manual extraction when no code action is available. Validates captured variables, scope shadowing, and compilation after extraction.
argument-hint: "[file-path] [start-line] [end-line] [new-function-name]"
user-invocable: true
allowed-tools: mcp__lsp__list_symbols mcp__lsp__suggest_fixes mcp__lsp__execute_command mcp__lsp__apply_edit mcp__lsp__get_diagnostics mcp__lsp__open_document mcp__lsp__format_document mcp__lsp__get_server_capabilities
license: MIT
compatibility: Requires the agent-lsp MCP server (github.com/blackwell-systems/agent-lsp)
metadata:
  required-capabilities: codeActionProvider
  optional-capabilities: documentFormattingProvider documentSymbolProvider
---

> Requires the agent-lsp MCP server.

# lsp-extract-function: Extract Code Block into a Named Function

**This skill RESTRUCTURES existing code** — it takes code that already exists
and moves it into a new function. This is distinct from `/lsp-generate`, which
creates NEW code that does not yet exist (stubs, mocks, interface implementations).
Use this skill when the code is already written; use `/lsp-generate` when you
need to generate code from scratch.

**Invocation:** User provides `file_path` (absolute path), `start_line` and
`end_line` (1-indexed range), and `new_function_name` (desired name for the
extracted function).

---

## Prerequisites

If LSP is not yet initialized, call `mcp__lsp__start_lsp` with the workspace
root first. Auto-inference applies when file paths are provided, but an explicit
start is required when switching workspaces.

---

## Step 1 — Get context (document symbols)

Call `mcp__lsp__open_document` to open the file, then call
`mcp__lsp__list_symbols` to understand the containing function and scope:

```
mcp__lsp__open_document({ "file_path": "<file_path>" })
mcp__lsp__list_symbols({ "file_path": "<file_path>" })
```

This establishes:
- Which function contains the selection
- Whether `new_function_name` already exists in the file (name collision check)

**Mandatory name collision check:** If `new_function_name` already exists as a
symbol in the document symbols list, report the conflict and stop immediately:

> Cannot extract: function `new_function_name` already exists in this file.
> Choose a different name and retry.

---

## Step 2 — Check server capabilities

Call `mcp__lsp__get_server_capabilities` to understand what the language server
supports:

```
mcp__lsp__get_server_capabilities({})
```

Check for `codeActionProvider` in the response. Note whether `execute_command`
is listed in `executeCommandProvider.commands`. This determines whether the
primary path (Step 3) is available.

---

## Step 3 — Primary path: LSP code action

Call `mcp__lsp__suggest_fixes` with the selection range:

```
mcp__lsp__suggest_fixes({
  "file_path": "<file_path>",
  "start_line": N,
  "start_column": 1,
  "end_line": M,
  "end_column": 999
})
```

Filter the returned actions for extract-function actions: include any action
whose `kind` contains `"refactor.extract"` OR whose `title` contains both
"Extract" and "function" (case-insensitive).

**If an extract-function action is found:**
- Display the action title to the user
- If the action proposes a different name than `new_function_name`, ask for
  confirmation before proceeding
- Execute via `mcp__lsp__execute_command` if the action has a `command` field:
  ```
  mcp__lsp__execute_command({
    "command": "<action.command.command>",
    "arguments": <action.command.arguments>
  })
  ```
- OR apply directly via `mcp__lsp__apply_edit` if the action has an `edit` field:
  ```
  mcp__lsp__apply_edit({ "workspace_edit": <action.edit> })
  ```
- Skip to Step 5 after applying.

**If no extract-function action is found:** fall through to Step 4 (manual fallback).

---

## Step 4 — Manual fallback

When no code action is available, perform manual extraction:

### a) Analyze the selection

Read the selected lines (`start_line` through `end_line`) and identify:
- **Parameters:** Variables used inside the selection that are declared outside
  (captured from outer scope — must become function parameters)
- **Return values:** Variables declared inside the selection that are used outside
  (must be returned from the extracted function)
- **Early returns:** Return statements inside the selection (the extracted function
  must wrap these)

### b) Construct and confirm the proposed signature

Build the extracted function signature based on the captured variables analysis.
Display the proposed signature to the user before writing:

> Proposed extraction:
> ```
> func new_function_name(param1 Type1, param2 Type2) (ReturnType, error) {
>     // selected lines
> }
> ```
> Proceed with this signature? [y/n]

Wait for user confirmation before applying any edit.

### c) Apply the extraction (order matters)

Apply edits sequentially — do NOT batch edits from different line regions into a
single `apply_edit` call:

1. **First:** Replace the selected lines with a call to the new function:
   ```
   mcp__lsp__apply_edit({
     "workspace_edit": {
       "changes": {
         "<file_path>": [{
           "range": { "start": { "line": start_line-1, "character": 0 },
                      "end":   { "line": end_line,     "character": 0 } },
           "newText": "    result := new_function_name(args...)\n"
         }]
       }
     }
   })
   ```

2. **Second:** Insert the new function definition after the containing function's
   closing brace:
   ```
   mcp__lsp__apply_edit({
     "workspace_edit": {
       "changes": {
         "<file_path>": [{
           "range": { "start": { "line": insert_line, "character": 0 },
                      "end":   { "line": insert_line, "character": 0 } },
           "newText": "\nfunc new_function_name(params) ReturnType {\n    ...\n}\n"
         }]
       }
     }
   })
   ```

Apply call-site replacement first, then insert the new function. This order
preserves line numbers during editing: replacing call site does not shift the
insertion point for the new function definition.

---

## Step 5 — Validate

After extraction via either path:

### 1. Check diagnostics

```
mcp__lsp__get_diagnostics({ "file_path": "<file_path>" })
```

If errors are reported, display them with the table of common causes below.

### 2. Common post-extraction errors

| Error type | Likely cause | Fix |
|------------|--------------|-----|
| Undefined variable | Captured var not passed as parameter | Add parameter |
| Type mismatch | Return type inferred incorrectly | Adjust return type in signature |
| Name shadows outer | New function name matches outer scope | Choose different name |
| Unused variable | Return value not captured at call site | Add variable at call site |

### 3. Format the document

```
mcp__lsp__format_document({ "file_path": "<file_path>" })
```

This cleans up indentation introduced by the extraction.

---

## Output Format

After completing extraction, display:

```
## Extraction Summary
- File:           path/to/file.go
- Extracted:      lines N–M
- New function:   new_function_name
- Path used:      LSP code action / Manual fallback
- Post-extraction errors: 0
```

Follow with the Diagnostic Summary if any errors changed (format in
[references/patterns.md](references/patterns.md)).

---

## Language-Specific Notes

- **Go:** gopls may offer "Extract function" in code actions for selection ranges.
  Check code actions first; gopls support varies by version.
- **TypeScript/JavaScript:** typescript-language-server may offer "Extract to function in global scope"
  or "Extract to inner function" — filter for these titles in Step 3.
- **Python:** pylsp and pyright-langserver typically do NOT offer extract-function
  code actions. Manual fallback (Step 4) is required for Python files.

Files in this skill

  • SKILL.md7.8 KB
  • references/patterns.md1.9 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.