Get type info / docs at a Swift source position
swiftGetHoverInfoGet hover information for Swift source code at a given line and character position, including declaration fragment. Use to check whether a closure's self capture can cause a retain cycle.
Instructions
[mg.code] SourceKit-LSP textDocument/hover at a (line, character) position. Returns the markdown / plaintext hover content plus a best-effort extracted declaration fragment. Use to disambiguate self captures: a class self in a closure can leak; a struct self can't.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| filePath | Yes | Absolute path to a Swift source file. | |
| line | Yes | Zero-based line number (LSP convention). | |
| character | Yes | Zero-based UTF-16 character offset within the line. | |
| projectRoot | No |
Implementation Reference
- src/tools/swift/getHoverInfo.ts:33-48 (handler)Main tool handler: resolves file path, acquires SourceKit-LSP client, calls lspHover, extracts typeName, and returns result.
export async function swiftGetHoverInfo( input: SwiftGetHoverInfoInput, ): Promise<SwiftGetHoverInfoResult> { const file = resolvePath(input.filePath); if (!existsSync(file)) { throw new Error(`File not found: ${file}`); } const root = input.projectRoot ? resolvePath(input.projectRoot) : projectRootFor(file); const client = await acquireClient(root); const result = await lspHover(client, file, input.line, input.character); const contents = result?.contents ?? ""; const typeName = extractTypeName(contents); return { ok: true, filePath: file, contents, typeName }; } - src/tools/swift/getHoverInfo.ts:7-20 (schema)Zod schema for input validation: filePath (string), line (int), character (int), optional projectRoot.
export const swiftGetHoverInfoSchema = z.object({ filePath: z.string().min(1).describe("Absolute path to a Swift source file."), line: z .number() .int() .nonnegative() .describe("Zero-based line number (LSP convention)."), character: z .number() .int() .nonnegative() .describe("Zero-based UTF-16 character offset within the line."), projectRoot: z.string().optional(), }); - Result type interface: ok, filePath, contents (markdown/plaintext hover), optional typeName (best-effort declaration fragment).
export interface SwiftGetHoverInfoResult { ok: boolean; filePath: string; /** Markdown / plaintext hover content from SourceKit-LSP. */ contents: string; /** Best-effort extracted declaration fragment (e.g. "class DetailViewModel : ObservableObject"). */ typeName?: string; } - src/index.ts:469-481 (registration)MCP server registration: tool name 'swiftGetHoverInfo', title, description, inputSchema, and handler that invokes swiftGetHoverInfo.
server.registerTool( "swiftGetHoverInfo", { title: "Get type info / docs at a Swift source position", description: "[mg.code] SourceKit-LSP `textDocument/hover` at a (line, character) position. Returns the markdown / plaintext hover content plus a best-effort extracted declaration fragment. Use to disambiguate `self` captures: a class self in a closure can leak; a struct self can't.", inputSchema: swiftGetHoverInfoSchema.shape, }, async (input) => { const result = await swiftGetHoverInfo(input); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] }; }, ); - Helper function to extract a type/declaration name from hover markdown content using regex.
function extractTypeName(hover: string): string | undefined { // Hover output usually leads with a code fence containing the // declaration line (e.g. "let foo: Bar" or "class Baz : Quux"). const m = hover.match( /\b(class|struct|enum|protocol|actor|func|var|let)\s+\S+/, ); return m ? m[0] : undefined; }