Announcing Beacon: Self-improving memory for coding agents
← All MCP servers
MCP server

Claude FAF

mcp:wolfe-jam/claude-faf-mcp

Persistent project context for Claude. IANA-registered .faf format.

Verdict
Suspicious

Risky behavior the analysis could not rule out.

Analyzed Oct 26, 2026, 12:31 UTC at c12e6dd

Dispute security verdict

If you believe this verdict is incorrect, submit a dispute and we'll review it.

1
findings
high
highest severity
1
threat classes
157
files scanned
1,763/1,763
checks satisfied
0
package advisories

Why this verdict

  • suspicious: finding mcp-server:.:worker/index.js:8:SUPPLY

Security findings 1

Supply chain

highContextual risklow confidence

The Cloudflare worker redirects /mcp and /sse endpoints to a third-party host (mcpaas.live), so clients using this endpoint talk to a remote server that is not part of the reviewed code; this is undeclared and its behavior is unknowable here.

return Response.redirect("https://mcpaas.live/claude/mcp/v1", 308);
conceal:remotevector:code
Counter-argument considered

The worker redirects the /mcp and /sse endpoints to a third-party host that is not part of the reviewed code. No declaration or mitigation is shown that clears this.

Open questions 7

What the analysis could not settle from the code alone.

The implementation of faf_setup, faf_tri_sync (which writes MEMORY.md under ~/.claude) and faf_git (which clones a repo by URL) is not shown here. Do they behave as documented and stay within the declared scope?
Persistence
What command does HOOK_COMMAND / setupSessionHook install into .claude/settings.json, and is it safe (fixed faf hook command)?
Persistence
faf_git passes a user-supplied URL to gitContextCommand, whose implementation is not shown. What it fetches and writes to the output folder is unknown.
Supply chain
[file request src/handlers/tools.ts] Find the definitions of HOOK_COMMAND and setupSessionHook: what command does the SessionStart hook run, and how does it merge into settings.json?
Persistence
[file request src/handlers/tools.ts] Review handleFafGit: how is the git clone invoked (shell vs argv, URL validation, hooks/config disabled) and is cloned content ever executed?
Code execution
[file request src/handlers/tools.ts] How do callTool and the faf_setup, faf_tri_sync, faf_git and faf_read handlers resolve paths, enforce confirm gates, and what do they write, read, or send off-host?
Persistence
[file request src/server.ts] How are the faf_setup, faf_tri_sync, faf_git, and faf_read tools implemented, and do path guards and the confirm gates hold?
Persistence
Refuted findings 24

Candidates the review stage examined and rejected, kept for transparency.

Persistence

criticalRefutedmedium confidence

The faf_setup tool writes a SessionStart hook into the project's .claude/settings.json, an agent control-plane file, so each later Claude Code session runs the faf hook; this is declared, previews first and needs confirm:true.

Install the native SessionStart hook in the project settings (<project>/.claude/settings.json)
Why it was refuted

Installing the SessionStart hook is the declared core function of faf_setup. It previews first, writes only with confirm: true, and touches only its own entry.

Persistence

criticalRefutedmedium confidence

The agent card's faf_setup tool description declares writing a hook to <project>/.claude/settings.json, an agent control-plane write that persists code execution at each Claude Code session start.

Install the native SessionStart hook in the project settings (<project>/.claude/settings.json)
Why it was refuted

The agent card declares the hook write openly as the faf_setup tool. It is preview-first, confirm-gated and limited to faf's own entry.

Persistence

criticalRefutedlow confidence

The manifest's faf prompt template tells the agent to call faf_tri_sync and faf_setup in its flow, which writes agent memory and installs a session hook; the user invokes the prompt, so this is an agent-driven control-plane write rather than hidden steering.

then faf_sync and faf_tri_sync, and faf_setup for the session hook.
Why it was refuted

The user-invoked prompt names faf_setup openly. faf_setup only previews unless confirm: true is passed, so this is not concealed steering or an unauthorised write.

Persistence

criticalRefutedmedium confidence

faf_setup writes a SessionStart hook entry into the project's .claude/settings.json (agent control plane). It is documented and requires a preview and confirm:true, but it still persists an auto-run command.

only faf's SessionStart hook entry
Why it was refuted

PRIVACY.md openly lists the single hook entry written by faf_setup after a preview and confirm. It is the declared core capability.

Supply chain

criticalRefutedmedium confidence

The SessionStart hook that faf_setup installs runs an unpinned `npx -y claude-faf-mcp` on every session, so whatever the latest npm release contains executes automatically.

npx -y claude-faf-mcp --session-refresh
Why it was refuted

The README states the unpinned hook command and tells users how to pin. The hook runs the project's own package and is installed only on explicit confirm, so it is declared core behavior.

Persistence

criticalRefutedmedium confidence

faf_setup writes a SessionStart hook into the project's .claude/settings.json whose command is `npx -y claude-faf-mcp --session-refresh`, so every future Claude Code session automatically fetches and runs an unpinned npm package; the write is confirm-gated, previewed first, and documented.

npx -y ${HOOK_FINGERPRINT}
Why it was refuted

The hook command is the declared product of faf_setup. It is confirm-gated, previewed first, and the README discloses that it runs the latest release.

Persistence

criticalRefutedlow confidence

The built-in `faf` prompt directs the agent to call faf_setup, which installs a session hook in the project's .claude/settings.json; the prompt states it previews first and writes only with confirm: true.

installs the SessionStart hook in the project settings
Why it was refuted

The prompt openly states that faf_setup previews first and writes only with confirm: true, never silently. Installing the hook is the tool's declared core capability, so it is neither concealed nor undeclared.

Code execution

criticalRefutedlow confidence

faf_git clones a user-supplied remote repo and runs faf-cli detection on it, then can write project.faf; remote content reaches parsing and a file write, but no execution of cloned code is shown in this batch.

An existing project folder to write project.faf into (a new file only).
Why it was refuted

The tool description declares the network clone into a removed temp folder and a write of project.faf only as a new file. The quoted line is a path-parameter description. No execution of cloned code is shown, so the chain fails.

Persistence

criticalRefutedlow confidence

faf_tri_sync writes a faf block into Claude Code's per-project MEMORY.md under ~/.claude (or CLAUDE_CONFIG_DIR), populated from project.faf contents. This is a declared feature, but the memory file is loaded into future agent sessions.

const result = writeClaudeMemory(projectDir, data);
Why it was refuted

The MEMORY.md write is the declared core capability of faf_tri_sync. It refuses the home folder and the filesystem root, and it reads the file back to verify that Claude's own notes are preserved.

Persistence

criticalRefutedmedium confidence

The faf_setup tool installs a SessionStart hook into the project's .claude/settings.json (agent control plane) that runs on every Claude Code session, but it is a disclosed, preview-by-default feature requiring confirm: true and refuses the home folder.

Install the native SessionStart hook in the project settings (<project>/.claude/settings.json)
Why it was refuted

The hook install is the declared purpose of faf_setup. The tool shows a preview first, writes only with confirm: true, and refuses the home folder, so it is not undeclared.

Persistence

highRefutedlow confidence

The faf_tri_sync tool writes content into Claude Code's per-project MEMORY.md under ~/.claude, which is agent memory loaded into later sessions; this is declared and limited to a managed block.

Write project.faf as a faf-managed block into the MEMORY.md Claude Code loads for this project
Why it was refuted

Writing the managed block into Claude's MEMORY.md is the openly declared purpose of faf_tri_sync, and the description limits changes to that block.

Persistence

highRefutedlow confidence

The faf_setup tool writes a SessionStart hook into the project's .claude/settings.json (agent control plane) when confirm is true; this is a documented, preview-by-default feature, but it persists a command that runs at every session start.

`confirm: true` merges non-destructively into the project's `.claude/settings.json`
Why it was refuted

The changelog documents faf_setup as the explicit, preview-by-default hook installer. This is the declared core capability, not a hidden write.

Persistence

highRefutedlow confidence

The faf_setup tool writes a SessionStart hook into the project's .claude/settings.json that runs an npx command at every session start, which is an agent control-plane write. It is gated behind confirm: true, previews first, and removes only its own entry.

faf_setup — the explicit installer of the SessionStart hook.
Why it was refuted

The file is the declared explicit installer. The source comment shows the write is confirm-gated and limited to faf's own entry in the project settings.

Persistence

highRefutedlow confidence

faf_setup, once confirmed, installs a SessionStart hook that runs an unpinned `npx -y claude-faf-mcp --session-refresh` at every Claude Code session start, so a compromised or changed npm package would execute automatically.

export const HOOK_COMMAND = `npx -y ${HOOK_FINGERPRINT}`;
Why it was refuted

The unpinned npx hook is documented in the README and installed only by the explicit, confirm-gated faf_setup. This is the declared core capability.

Persistence

highRefutedlow confidence

The declared faf_setup tool writes a SessionStart hook into the project's .claude/settings.json (agent control plane) whose command is an unpinned `npx -y claude-faf-mcp --session-refresh`; it is documented and gated on confirm:true, with a preview and safe removal.

writes the PROJECT settings file, `<project>/.claude/settings.json
Why it was refuted

The header comment documents the project-settings write as the explicit installer behavior, gated on confirm: true, and the README discloses the unpinned command. This is the declared core capability.

Persistence

highRefutedlow confidence

exportFormat writes faf-managed blocks, rendered from project.faf and repo enrichment, into agent rules and memory files (AGENTS.md, .cursorrules, GEMINI.md, copilot-instructions) that other agents load as instructions; this is the declared core function and keeps content outside the block.

cli.writeCursorrules(dir, data)
Why it was refuted

Writing faf-managed blocks into AGENTS.md, .cursorrules and similar files is the declared core export function. PRIVACY.md lists each file, and content outside the block is preserved.

Persistence

highRefutedlow confidence

The faf_tri_sync tool writes a faf-managed block into Claude Code's per-project MEMORY.md under ~/.claude, which is outside the project folder and part of the agent control plane. This is a disclosed capability of the tool, so intent is plausibly honest.

Write project.faf as a faf-managed block into the MEMORY.md Claude Code loads for this project
Why it was refuted

Writing a faf-managed block into MEMORY.md is the tool's stated purpose and is named in its description. It is confined to the faf block, so the behavior is declared core capability, not concealed.

Persistence

highRefutedlow confidence

The faf_setup tool can install a hook into .claude/settings.json (agent control plane). It previews by default and writes only when confirm: true is passed, and the behavior is documented.

Preview by default; writes .claude/settings.json only on confirm: true.
Why it was refuted

faf_setup is a documented, preview-by-default installer that writes only with confirm: true. This is its declared core function, not undeclared.

Persistence

highRefutedlow confidence

faf_auto writes a faf-managed block into the project's CLAUDE.md, an agent instruction file, derived from project.faf. This is the declared core function, but it modifies an agent control-plane file.

const written = await writeClaudeFromFaf(cwd, data, legacyProject);
Why it was refuted

faf_auto's CLAUDE.md write is the declared core function, and only the faf-managed block changes.

Persistence

highRefutedlow confidence

faf_tri_sync writes a faf-managed block into Claude Code's own MEMORY.md (an agent memory file under ~/.claude), which is an agent control-plane write; it is a disclosed tool function, but it modifies agent memory outside the project folder.

const { writeClaudeMemory, claudeMemoryStatus, resolveClaudeMemoryPath, isNonProjectRoot } = await fafCli;
Why it was refuted

The flagged line only destructures helper functions from faf-cli and writes nothing itself. The MEMORY.md write is declared in the tool description as its core function.

Data exfiltration

mediumRefutedlow confidence

Changelog for 5.3.0 adds persistent usage/download analytics via Upstash Redis, which sits against the 5.0.0 PRIVACY claim of 'no telemetry, no tracking'; later versions say the dependency was removed, so intent and reach are not fully established.

download and usage stats tracked across sessions
Why it was refuted

The finding rests only on a historical changelog line; it is documentation, not an instruction or code path, so no agent-directed chain or concrete exfiltration exists. The cited evidence shows no source-to-sink chain, and the analyst concedes later versions removed the dependency. It is a changelog entry, not concealed behavior.

Supply chain

mediumRefutedlow confidence

package.json declares npm install-time lifecycle scripts (postinstall runs scripts/postinstall.js; prepare runs a build); the shipped postinstall only prints a message to /dev/tty, so this is undeclared but benign-looking install-time code execution.

"postinstall": "node scripts/postinstall.js"
Why it was refuted

The postinstall script only prints a message to /dev/tty or stderr. The prepare script is a plain build, so there is no harmful install-time behavior.

Supply chain

mediumRefutedlow confidence

The Smithery start command runs the server via npx with an unpinned @latest tag, so whatever is currently published on the registry executes on the host.

args: ["-y", "claude-faf-mcp@latest"]
Why it was refuted

This is the server's own declared stdio launch via npx, as the description states. Launching the package under review is its core capability and adds no concealed behavior.

Supply chain

mediumRefutedlow confidence

The installed hook command runs `npx -y` on an unpinned package name at every Claude Code session start, so whatever version the registry or a local install resolves will execute; this is a documented, confirm-gated part of faf_setup.

export const HOOK_COMMAND = `npx -y ${HOOK_FINGERPRINT}`;
Why it was refuted

The finding itself calls the unpinned hook command documented and confirm-gated. The README explicitly discloses it, so it is declared core behavior.

Coverage gaps 2

Parts of the artifact the static analysis could not fully examine.

dynamic_metadata line 107: tools list returned by ListToolsRequestSchema handler is computed
src/server.ts
no_tools_extracted MCP server target with no statically extractable tools/prompts/resources
package.json