An MCP server that provides code indexing and symbol search capabilities for Xcode projects using the IndexStore database. Enables searching for symbols, finding occurrences, and navigating code relationships.
IndexStoreMCP demonstrates solid tool design with clear naming, comprehensive descriptions, and well-structured schemas. All 8 tools follow verb_noun patterns (loadIndex, searchSymbol, getOccurrences). Descriptions are detailed (100-250 chars) and include workflow guidance. Input schemas are explicit with typed properties and required fields. However, output schemas are not documented, LLMs cannot predict return structure. Error handling is minimal; tools lack recovery guidance. No tool annotations (readOnlyHint, idempotentHint) despite all being read-only operations. Parameter descriptions are strong but could specify ranges/constraints more formally (e.g., 'line must be ≥1').
Use after obtaining a USR. Returns every location in the codebase where that symbol is defined, referenced, or called. Use the roles filter to narrow results.
Must be called first before any other tool. Loads the Xcode index for the given project. Only needs to be called once per session. Typical workflow: loadIndex → searchSymbol/searchSymbolPattern → getOccurrences/relatedOccurrences. Call refreshIndex after a build to pick up changes.
Polls the index store for unit changes and updates the database. Call this after a build to pick up changes to the codebase.
Use after obtaining a USR. Returns symbols related to the given symbol: conformances, overrides, extensions, and other relationships. Use the roles filter to narrow results.
Use when you know the symbol name. Returns one or more USRs. For types and properties, use the bare name (e.g. MyViewController, isLoading). For methods, you can use either the bare name (e.g. viewDidLoad) or the full signature with labels (e.g. tableView(_:numberOfRowsInSection:)). Falls back to prefix matching if no exact match is found.
Use when searchSymbol returns no results or you only know a partial name. Performs subsequence matching — e.g. 'mvc' matches 'MyViewController'. Results may include matches from dependencies. Use anchorStart/anchorEnd and longer patterns to narrow results.
Output schemas not documented. LLMs cannot predict return structure (fields, types, pagination). Tools return unstructured text via CallTool.Result.success(text), forcing LLMs to parse free-form responses.
No tool annotations despite all tools being read-only. Missing readOnlyHint and idempotentHint annotations prevent agents from understanding safety properties and retry semantics.
Error handling lacks recovery guidance. Tools return plain text errors via CallTool.Result.failure(text) with no categorization (retryable vs fatal) or actionable next steps for LLMs.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 62 | 2026-07-28+ | v2 |
Use when reading a file and you want the USR of a symbol at a specific position. More precise than searchSymbol when the name is ambiguous (e.g. init). Returns the single closest symbol at or before the given column.
Returns all symbols defined in a given source file, optionally filtered by role. Useful for exploring a file's structure.
Parameter constraints not formalized. Descriptions mention defaults (e.g., 'Defaults to false') but lack explicit min/max, regex patterns, or enum constraints in schema. Line/column parameters lack range documentation.
No pagination support documented. Tools like getOccurrences and relatedOccurrences may return large result sets but lack limit/offset parameters or total count in responses.