Stop your agent grepping F#. Give it the real compiler: cross-project find, a trustworthy check verdict, types, rename, dead-code — over MCP.
An agent working a real task against examples/quickstart — set_project → check (clean) → find (17 cross-project sites). Real MCP calls, no grep.
Text search misses the semantics F# depends on — partial application, aliased opens, shadowed bindings, cross-project uses, record-field set-sites, CE custom-operations — and over-matches comments and strings. FsLangMCP resolves symbols via the real compiler (FCS in-process + FSAC LSP), so your agent gets trustworthy answers instead of grep noise.
In a live-execution A/B, shaping the tool surface to agent intent cut agents' rg/grep-fallback from 56% → 28% and steps-to-completion from 10.4 → 5.8 (success rate 89% → 100%). Full story: docs/why-agents-grep-fsharp.md.
Prerequisites: .NET SDK 10+ on PATH.
dotnet tool install -g FsLangMcp
fslangmcp --bootstrap-toolsBootstrap reads the manifest embedded in the installed FsLangMCP binary and
installs (or downgrades) FSAC, ProjInfo, and Fantomas to the exact reviewed
versions for that release. It also creates the dotnet-fantomas command alias
required by FSAC formatting.
Add to your MCP client config:
{
"mcpServers": {
"fslangmcp": { "command": "fslangmcp" }
}
}Then call set_project with your .fsproj or .sln path, and start with find or check.
Full setup: docs/getting-started.md · Per-client configs: docs/configuration.md · Runnable examples: examples/.
35 tools in 8 groups. Full reference: docs/tools-reference.md.
| Tool | What it does |
|---|---|
find |
Multi-project semantic search with explicit coverage. A failed/timed-out project makes absence indeterminate instead of returning a false matched=false. |
check |
One trustworthy verdict (clean/errors/unknown). Default mode is a fresh FCS check; fast FSAC mode returns clean only with complete current coverage. Project scope warns that downstream consumers were not checked; workspace scope requires a solution or directory. |
| Tool | What it does |
|---|---|
set_project |
Initialize or switch FSAC/LSP context. Results are bound to the active project and session generation; a no-restart cross-project switch is rejected. |
project_health |
Fast read-only preflight: options readiness, source files, analyzer setup, test project discovery. No build, no tests. |
fcs_project_outline |
Compact project-wide outline over all compile files. |
fcs_file_outline |
Per-file outline with attributes, bounded/truncation-aware CustomOperation and diagnostic arrays, and a hard serialized-response guard; summaryOnly=true (default) keeps token cost low. |
fsharp_project_inspect |
Read-only .fsproj inspection: compile order, references, signature/implementation pairing. |
fcs_symbol_at_word |
Tolerant symbol lookup by line + word — no exact cursor column needed. |
fcs_get_project_options |
Get compiler OtherOptions for a .fsproj via proj-info. Diagnostic helper. |
| Tool | What it does |
|---|---|
fcs_explain_diagnostic |
Plain-language explanation + repair hints for a compiler diagnostic code (e.g. FS0039). |
fcs_diagnostic_fixes |
Fetch a file's diagnostics and request code-action fixes, grouped per diagnostic. |
fcs_check_compile_order |
Detect when FS0039 is a compile-order problem, not a missing open. |
fcs_suggest_open |
Given an unresolved symbol name, return ranked open directive candidates. |
| Tool | What it does |
|---|---|
fcs_rename_preview |
Preview a semantic rename's full impact (edits grouped by file, with before/after text) without writing. |
fcs_refactor_impact |
Blast-radius preview: uses, tests, compile order, public API — all orchestrated in one call. |
fcs_make_internal_visible |
Drop private from a declaration at a position; returns a workspace edit, writes nothing. |
fcs_tests_for_symbol |
List the tests that likely cover a symbol (test-file uses + enclosing test name). |
| Tool | What it does |
|---|---|
fcs_dead_code |
List likely-unused private/internal bindings as cleanup candidates. |
fcs_review_scan |
Scan source for AST-level review candidates: match wildcards, mutable, blocking calls, casts, reflection. |
fcs_public_api |
Emit the project's full public API surface in stable order — useful for API-diff snapshots. |
fcs_signature_status |
Report .fsi-vs-impl drift: members hidden from signature or stale in signature. |
fcs_create_file_plan |
Plan where a new .fs file belongs in compile order; writes nothing. |
| Tool | What it does |
|---|---|
fcs_analyzer_diagnostics |
Report F# analyzer diagnostics (SARIF-backed, grouped by analyzer and severity). |
fcs_analyzer_setup_preview |
Plan what to add to enable analyzers in a .fsproj; writes nothing. |
| Tool | What it does |
|---|---|
fcs_nuget_types |
Enumerate types in one referenced assembly, by NuGet package id or by the assembly SimpleName it ships (exact, case-insensitive). |
fcs_nuget_members |
Enumerate members of one type, including metadata accessibility, abstractness, and generic constraints. |
fcs_referenced_symbols |
Substring search across all referenced assemblies (NuGet + framework). |
The raw textDocument_* tools and fsharp_signature_data require set_project
and LSP readiness. fcs_signature_help runs in-process with FCS project context.
Prefer the semantic tools above for free-form agent flows.
| Tool | What it does |
|---|---|
textDocument_completion |
Raw LSP completion at an exact position. |
textDocument_formatting |
Raw LSP formatting via Fantomas; returns edits, does not write to disk. |
textDocument_codeAction |
Raw LSP code-action proxy (with empty diagnostic context). |
textDocument_rename |
Raw LSP semantic rename; returns WorkspaceEdit. |
fcs_signature_help |
Exact-position FCS signature help around a call site. |
fsharp_signature_data |
Structured FSAC fsharp/signatureData at an exact call-site position. |
| Tool | What it does |
|---|---|
fslangmcp_version |
Returns installed version. Zero-arg. Use when filing UX feedback. |
fsharp_runtime_status |
Read-only runtime snapshot: heap/GC, FCS cache, project-options load/reload telemetry, FSAC working set, and process.threads; emits a heuristic restart warning above the anomalous thread threshold. |
1. set_project {"projectPath": "/abs/path/MyApp.sln"}
→ readiness.lsp=true, loadedProjects=[...], fslangmcpVersion="0.16.0"
2. check {}
→ verdict="clean"
3. find {"query": "OrderId", "kind": "definition"}
→ [Domain/Order.fs:12 definition `type OrderId = ...`, ...]
4. fcs_file_outline {"path": "/abs/path/Domain/Order.fs"}
→ module/type headers, memberCounts by kind
5. fcs_rename_preview {"path": "/abs/path/Domain/Order.fs", "line": 12, "character": 5, "newName": "OrderIdentifier"}
→ edits grouped by file, totalEdits=7, crossProject=false
Command-line args:
--project <path>/-p <path>— pre-load a project on startup--fsac-command <cmd>— override thefsautocompleteexecutable--fsac-args "<args>"— pass extra args to FSAC--bootstrap-tools— install/update the exact supported global runtime-tool versions--version— print the packaged FsLangMCP version and exit
Environment fallbacks: FSAC_COMMAND, FSAC_ARGS, FSA_PROJECT_PATH.
FsLangMCP ships with Workstation GC + Concurrent GC baked in via runtimeconfig.template.json. This is the recommended profile for stdio MCP servers per FsMcp's runtime tuning guide: FCS workloads are bursty (load → idle → next request), and Server GC's "don't release until OS pressure" produces alarming RSS growth on dev laptops. Override if needed:
DOTNET_gcServer=1— opt into Server GC (higher throughput, holds memory longer)DOTNET_GCHeapHardLimitPercent=0xA— cap heap at 10% of RAM (either GC mode)
Installed tool:
{
"mcpServers": {
"fsharp": {
"command": "fslangmcp",
"args": ["--project", "/absolute/path/to/App.fsproj"]
}
}
}Local dev (without install):
{
"mcpServers": {
"fsharp": {
"command": "dotnet",
"args": [
"run", "--project", "/path/to/FsLangMcp.fsproj",
"--", "--project", "/absolute/path/to/App.fsproj"
]
}
}
}Pass projectPath explicitly on every FCS tool call — FCS tools cache project-wide results per resolved .fsproj, so agents targeting different projects share no stale caches.
{ "path": "/absolute/path/to/File.fs", "projectPath": "/absolute/path/to/App.fsproj" }Concurrency limits:
FSLANGMCP_MAX_CONCURRENT_FCS=2- LSP tools are always serialized. FSAC owns one mutable workspace, so LSP concurrency is intentionally not configurable.
Process and RPC timeouts (milliseconds):
FSLANGMCP_LSP_STARTUP_TIMEOUT_MS=60000FSLANGMCP_LSP_REQUEST_TIMEOUT_MS=30000FSLANGMCP_PROJ_INFO_TIMEOUT_MS=120000FSLANGMCP_BOOTSTRAP_TIMEOUT_MS=300000FSLANGMCP_PROCESS_OUTPUT_LIMIT_CHARS=4194304(per redirected stream; excess output is drained but not retained)
- Success:
{"status": "ok", ...fields}or{"status": "ok", "result": <payload>} - Not ready:
{"status": "not_ready", "message": "..."}— FSAC workspace still loading - Wrong FSAC context:
{"status": "context_mismatch", "contextMatched": false, ...} - Restart required:
{"status": "restart_required", ...}— a live FSAC belongs to another project and the requested no-restart switch was not applied - Invalid args:
{"status": "invalid_args", "message": "..."}— required arg blank/missing - Infrastructure failure:
{"status": "infrastructure_error", "errorKind": "...", "message": "..."}
set_project keeps the boolean readiness flags for compatibility and adds
readiness.symbolIndexState / readiness.symbolIndexHint when the symbol index
is not ready. lspRestartRequested reports intent; legacy lspRestarted keeps
mirroring that request, while lspReplacedExistingProcess reports whether a
running FSAC process was actually replaced. FSAC-derived responses include
activeProjectPath, contextMatched, and sessionGeneration.
find has its own completeness contract: status="partial" means matches were
found but some projects were not analyzed; status="unknown" plus
resolution.matched=null means absence could not be proven. check(speed="fast")
similarly exposes expected/received/missing/stale file coverage and never turns an
incomplete empty snapshot into clean.
LSP positions (line, character) are 0-based.
just restore
just check # build + tests
just analyze # F# analyzers via FSharp.Analyzers.BuildWired analyzers: Ionide.Analyzers, G-Research.FSharp.Analyzers, FSharp.Analyzers.Build.
For local development, restore the local analyzer tool:
dotnet tool restore- LSP proxy tools return
{"status": "not_ready"}if called beforefsautocompletefinishes loading.set_projectwaits up to 30 seconds for workspace readiness; the preceding RPC handshake has its own configurable 60-second timeout and kills/reset FSAC on expiry. - FCS does not expose cancellation once synchronous compiler work has started.
findand project/workspacecheckstill return at their requested deadline; identical retries share the real in-flight worker, while a different key is rejected as busy instead of joining an unbounded queue. The admitted worker may continue until FCS returns. Restart FsLangMCP to terminate a genuinely stuck in-process compiler operation. - FCS tools fall back to script-style inference (
GetProjectOptionsFromScript) only when no.fsprojis found. Diagnostics and symbol data can be incomplete for multi-project solutions in this mode. project_healthis project-focused — it does not inspect whole solutions or resolve ambiguous directories.dotnet tool update -g FsLangMcpdoes not affect an already-running server process — it's long-lived once your MCP client spawns it. Callfslangmcp_versionto confirm which version is actually running rather than assuming the on-disk one; version-sensitive testing needs a fresh MCP connection. Seedocs/troubleshooting.md.
dotnet tool packages cannot automatically install other global tools during
installation. The reviewed compatibility set is pinned in
dotnet-tools.json:
fsautocomplete0.83.0ionide.projinfo.tool0.74.2fantomas7.0.5
The FsLangMCP package dependency graph is audited separately from those external
tools. The latest available FSAC and Fantomas packages still carry
advisory-listed MessagePack assemblies, although the supported FsLangMCP paths
explicitly use JSON and do not select a MessagePack formatter. No patched
upstream tool package is currently available, so the exact pins above are a
documented, process-contained risk acceptance rather than a guarantee that every
file shipped inside the external tools is advisory-free. See the 0.14.0
section of the changelog for the advisory links and scope (that work ships to
consumers as part of 0.15.0; 0.14.0 was never published).
Install that exact set (including FSAC's required Fantomas command alias) for normal use:
fslangmcp --bootstrap-toolsFor repository development, just runtime-tools materializes the same versions
under .runtime-tools/, and just live-fsac performs a real MCP → FSAC and
ProjInfo smoke. Both paths validate the same exact root manifest; the repository
path is isolated from any other globally installed tools.
