MCP stdio bridge for the VitaSound Forth tooling family: fmix, flint, fcov.
Console-only utility (Gforth). fmcp serve runs one long-lived Gforth process that
reads newline-delimited JSON-RPC on stdin and writes NDJSON responses on stdout.
git clone git@github.com:VitaSound/fmcp.git
cd fmcp && fmix packages.getAdd to ~/.bashrc (or ~/.zshrc) — two lines for this tool only (do not merge PATH with fmix/flint/fcov):
export FMCP_HOME="<install-dir>/fmcp"
export PATH="$FMCP_HOME/bin:$PATH"<install-dir> is the parent of your clones. fmcp also needs fmix, flint, and fcov on PATH — each with its own two-line block. Bulk install: VitaSound/feco — ./scripts/clone-ecosystem.sh. Canonical rules: feco shell setup.
Then source ~/.bashrc and run fmcp version.
fmcp help
fmcp version
fmcp serve # MCP server (for Cursor)Serve diagnostics logging is off by default. Enable with FMCP_LOG set to a file path, or FMCP_LOG=1 / on for $FMCP_HOME/.fmcp/serve.log. Disable explicitly with FMCP_LOG=0, off, or false. Per-repo tool calls append to $project_root/.fmcp/tool.log only when logging is enabled. See AGENTS.md for post-mortem use after Connection closed.
Temporary files under /tmp/fmcp-* are removed after each capture and at session end; stale files older than 60 minutes are swept at session start (FMCP_CLEANUP_TMP=0 to disable).
Which file to edit? In the UI, Cursor opens the config for your session:
| How you work | File Cursor edits |
|---|---|
Remote WSL (workspace under /home/...) |
~/.cursor/mcp.json inside Linux — use Linux paths below |
| Windows app, code lives in WSL | %USERPROFILE%\.cursor\mcp.json on Windows — use wsl.exe below |
Do not mix them: editing only the Linux file does nothing if Cursor runs MCP on Windows, and vice versa.
{
"mcpServers": {
"vitasound-forth": {
"command": "/home/sea/fmcp/bin/fmcp",
"args": ["serve"],
"env": {
"FMCP_HOME": "/home/sea/fmcp",
"FMIX_HOME": "/home/sea/fmix",
"FLINT_HOME": "/home/sea/flint",
"FCOV_HOME": "/home/sea/fcov",
"PATH": "/home/sea/fmcp/bin:/home/sea/fmix/bin:/home/sea/flint/bin:/home/sea/fcov/bin:/usr/local/bin:/usr/bin:/bin"
}
}
}
}Adjust /home/sea/... if your clones live elsewhere. "command": "fmcp" without PATH in env fails — Cursor does not load ~/.bashrc.
Optional wrapper (same env baked in): "command": "/home/sea/fmcp/bin/fmcp-cursor-serve", "args": [].
Cursor runs MCP on Windows and cannot use /home/... paths directly. Use wsl.exe and the wrapper script:
{
"mcpServers": {
"vitasound-forth": {
"command": "C:\\Windows\\System32\\wsl.exe",
"args": [
"-d",
"Ubuntu-22.04",
"-e",
"/home/sea/fmcp/bin/fmcp-cursor-serve"
]
}
}
}Edit -d to match wsl -l -v (distro name). Adjust the path if your clone is not under /home/sea/fmcp.
Config file on Windows: %USERPROFILE%\.cursor\mcp.json (e.g. C:\Users\You\.cursor\mcp.json).
bin/fmcp-cursor-serve exports FMCP_HOME, sibling tool homes, PATH, then exec fmcp serve.
Same JSON as Remote WSL above (~/.cursor/mcp.json with Linux paths).
{
"mcpServers": {
"vitasound-forth": {
"command": "/absolute/path/to/fmcp/bin/fmcp",
"args": ["serve"],
"env": {
"FMCP_HOME": "/absolute/path/to/fmcp",
"FMIX_HOME": "/absolute/path/to/fmix",
"FLINT_HOME": "/absolute/path/to/flint",
"FCOV_HOME": "/absolute/path/to/fcov",
"PATH": "/absolute/path/to/fmcp/bin:/absolute/path/to/fmix/bin:/absolute/path/to/flint/bin:/absolute/path/to/fcov/bin:/usr/local/bin:/usr/bin:/bin"
}
}
}
}Use an absolute path for command. Cursor does not load your shell ~/.bashrc, so "command": "fmcp" fails unless fmcp happens to be on the default PATH.
After mcp.json is set up, enable the server and teach the agent to call it.
- Settings → MCP — turn on
vitasound-forth. - Status must be connected (green). If not: Refresh, then check paths in
mcp.jsonand doc/API.md. - In chat you can ask: «List MCP tools from vitasound-forth» — expect
mcp_ping,shell_run,fmix_check,fmix_test,flint_lint,fmix_packages_get,fcov_run,fcov_report,gforth_eval.
Agents do not auto-prefer MCP. Add guidance in the workspace you code in (fmix, flint, fcov, …):
Option A — AGENTS.md in that repo (copy or link the MCP section from AGENTS.md):
## VitaSound tooling
Use MCP server **vitasound-forth** for packages, lint, tests, coverage.
Do not run `fmix test` / `flint` / `fcov` via terminal when MCP tools exist.
Order: `fmix_packages_get` → `fmix_check` (or `fmix_test` + `flint_lint` + optional `fcov_*`).
`project_root` = absolute path to this repo (e.g. `/home/sea/fmix`).Option B — Cursor rule (.cursor/rules/vitasound-forth.mdc in the target repo):
---
description: VitaSound Forth — use fmcp MCP tools
alwaysApply: true
---
Prefer MCP **vitasound-forth**: `fmix_packages_get`, `flint_lint`, `fmix_test`, `fcov_run`, `fcov_report`.
Pass `project_root` as the absolute package path. No ad-hoc shell for the same operations.Option C — one-off in chat:
Use vitasound-forth MCP for tests and lint;
project_root=/home/sea/fmix.
| Task | MCP tool | Not this |
|---|---|---|
| Fetch deps | fmix_packages_get |
fmix packages.get in shell |
| Lint | flint_lint |
flint lint in shell |
| Tests | fmix_test |
fmix test in shell |
| Coverage | fcov_run, fcov_report |
manual fcov CLI |
Full tool params and agent workflow: AGENTS.md.
bash tests/smoke_test.sh # fmcp protocol
bash tests/mcp_serve_log_test.sh # serve diagnostics log (SESSION_START, REQ, ping)
bash tests/mcp_cleanup_test.sh # /tmp/fmcp-* temp cleanup
bash tests/mcp_session_timeout_test.sh # timeout eval + ping in one session
bash tests/mcp_shell_run_timeout_test.sh # shell_run sleep + ping in one session
bash tests/mcp_fcov_session_test.sh # fcov_run timeout + ping in one session
bash tests/test_mcp_smoke.sh # optional Python reference MCPFollow frules (Gforth dialect). See AGENTS.md.
-
initialize,tools/list,tools/callover stdio (via fjson read-lite) -
fmcp_exec.4th—fmix_test,fmix_packages_get,flint_lint,fcov_run,fcov_report - Cursor agent guidance — AGENTS.md, README «Using MCP in the agent»
- Full E2E with real
FMIX_HOMEtool execution in CI
- doc/API.md — architecture, MCP methods/tools, module map, smoke E2E explained.
- CHANGELOG.md — release history.
- AGENTS.md — notes for AI agents working on this repo.
Two contours — do not mix them in one fcov run:
| Contour | Command | Purpose |
|---|---|---|
| Correctness | fmix test (isolated, default) |
Full regression: subprocess CLI, pipe serve, MCP tools |
| Coverage | ./tests/coverage_mcp_gate.sh |
fcov instrumentation + shared in-process tests + guards |
fmcp test # or: fmix test — isolated subprocess per *_test.4th
./tests/coverage_mcp_gate.sh # fcov clean → bin/fmcp test --shared → 100% gate
bash tests/smoke_test.sh # smoke E2E (stdio protocol, no Cursor)- Before every
fcov run:fcov clean(orrm -rf .fcov/callsif a run was killed). Check size:du -sh .fcov/calls— if > ~100 MB, subprocess storm; clean before aggregate. - Under fcov (
FCOV_CALLS_LOGset): subprocess tests skip viafmcp.under-fcov?— no nestedfmix test,fcov_run, CLI/pipe serve, orgforth_evalstorms. - Metric: production colon-defs in
fmcp_*.4th(nottests/); gate denylist excludes subprocess-only words (fmcp.run-isolated,fmcp.serve-stdio, exec wrappers, etc.) — seetests/coverage_gate_check.py.
Smoke E2E pipes NDJSON lines into fmcp serve and checks grep patterns —
see doc/API.md for details.