Skip to content

MCP Server

The SessionFS MCP server gives AI coding agents access to your session history and project knowledge base during conversations. Agents can search past sessions, read project context, and contribute knowledge back — building a shared memory that persists across tools and teammates.

Transports: stdio for local use (agent launches sfs mcp serve as a subprocess) and HTTP/SSE for remote use (cloud-hosted agents like claude.ai).

Run sfs mcp install --for <tool> to register the MCP server with your AI tool. This registers the server in the tool's MCP configuration and injects knowledge-contribution instructions into the tool's project config file (e.g., CLAUDE.md, .cursorrules).

Supported tools:

Terminal window
sfs mcp install --for claude-code # ~/.claude.json
sfs mcp install --for cursor # ~/.cursor/mcp.json
sfs mcp install --for codex # via codex mcp add
sfs mcp install --for gemini # via gemini mcp add
sfs mcp install --for copilot # ~/.copilot/config.json
sfs mcp install --for amp # ~/.amp/config.json
sfs mcp install --for cline # VS Code globalStorage
sfs mcp install --for roo-code # VS Code globalStorage
sfs mcp install --for kilo-code # VS Code globalStorage

To skip the instruction injection (server registration only):

Terminal window
sfs mcp install --for claude-code --skip-instructions

The MCP server exposes 68 tools in nine categories: Session, Knowledge Read, Knowledge Write, Rules, Personas (Pro+), Tickets (Team+), AgentRun (Team+), Handoffs (Pro+ for direct, Team+ for team handoffs), and Work Queues.

Search past AI coding sessions by keyword, error message, or file path.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | query | string | yes | Keywords, error messages, or file paths to search for | | tool_filter | string | no | Filter by source tool (claude-code, codex, gemini, cursor, copilot, amp, cline, roo-code, kilo-code) | | max_results | number | no | Maximum results to return (default: 5) |

Retrieve the full conversation from a specific session. Use after search_sessions finds a relevant hit.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | session_id | string | yes | Session ID in ses_... format | | max_messages | number | no | Limit messages returned (default: 50) | | summary_only | boolean | no | Return metadata only, no messages (default: false) | | audit_session_id | string | no | Current session id to append this retrieval to its audit log |

List recent sessions with optional filtering.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | limit | number | no | Max sessions to return (default: 10) | | tool_filter | string | no | Filter by source tool | | project_filter | string | no | Filter by project/workspace path substring |

Find sessions that touched a specific file or encountered a similar error. Provide file_path or error_text (at least one).

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | file_path | string | no | Find sessions that modified this file | | error_text | string | no | Find sessions with similar errors | | limit | number | no | Max results (default: 5) | | audit_session_id | string | no | Current session id to append this retrieval to its audit log |

Get a structured summary — files modified, commands run, tests executed, errors encountered, packages installed.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | session_id | string | yes | Session ID in ses_... format |

Get the LLM Judge trust audit — verifiable claims, verdicts (verified/unverified/hallucination), confidence scores, CWE mappings.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | session_id | string | yes | Session ID in ses_... format |

Return the instruction provenance recorded for a session — what rules and artifacts shaped the agent at capture time. Returns rules_version, rules_hash, rules_source (sessionfs / manual / mixed / none), and the instruction_artifacts list.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | session_id | string | yes | Session ID in ses_... format |

Return the retrieval audit log for a session. When start_ticket creates a server-side retrieval_audit_id, MCP retrieval tools append durable events to the SessionFS API; offline clients fall back to local JSONL when callers pass audit_session_id or set SESSIONFS_SESSION_ID / SFS_SESSION_ID. Each row records the tool name, arguments, timestamp, and returned IDs/slugs.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | session_id | string | yes | Session ID whose retrieval log should be returned |

Get the shared project context document — architecture decisions, conventions, wiki pages, and recent knowledge entries. Call early in a session to understand the project. Use get_context_section or get_wiki_page instead when you only need one slice — they return less and cost less.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | git_remote | string | no | Git remote URL (auto-detected from working directory if omitted) |

Return one section of the project context document by slug instead of the full document. If the slug is not found, the response lists the available slugs so you can retry.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | slug | string | yes | Section slug (lowercase, non-alphanumeric collapsed to _) | | git_remote | string | no | Git remote URL (auto-detected if omitted) | | audit_session_id | string | no | Current session id to append this retrieval to its audit log |

Read one wiki page's full content plus backlinks. Cheaper than get_project_context when you already know the page slug.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | slug | string | yes | Wiki page slug (e.g., architecture) | | git_remote | string | no | Git remote URL (auto-detected if omitted) | | audit_session_id | string | no | Current session id to append this retrieval to its audit log |

Return the revision history for a wiki page. Each revision carries revision_number, revised_at, the editing user_id, optional persona_name and ticket_id, and a content snapshot. Cursor-paginated for long histories.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | slug | string | yes | Wiki page slug | | git_remote | string | no | Git remote URL (auto-detected if omitted) | | cursor | string | no | Opaque pagination cursor returned as next_cursor from the previous call | | limit | number | no | Page size (default: 25) |

Search across knowledge entries and wiki pages by keyword. Use this when you have a query string. Use list_knowledge_entries instead when you want a filtered list with no query.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | query | string | yes | What to search for | | entry_type | string | no | Filter by type: decision, pattern, discovery, convention, bug, dependency | | limit | number | no | Maximum results (default: 10) | | audit_session_id | string | no | Current session id to append this retrieval to its audit log |

Filtered list of knowledge entries with pagination. Useful when you want to browse by type, claim class, freshness, or origin session without a search query.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | entry_type | string | no | One of decision, pattern, discovery, convention, bug, dependency | | claim_class | string | no | evidence, claim, or note | | freshness_class | string | no | current, aging, stale, or superseded | | dismissed | boolean | no | Include dismissed entries (default: false) | | session_id | string | no | Only entries linked to this session | | sort | string | no | created_at_desc (default), last_relevant_at_desc, confidence_desc | | page | number | no | 1-based page number (default: 1) | | limit | number | no | Page size, max 200 (default: 50) |

Return one knowledge entry's full record, including last_relevant_at for stale review.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | id | number | yes | Knowledge entry ID |

One call for the dashboard banner data — counts and recommended next actions. Each count mirrors a precise compile-pipeline filter so MCP agents read the same contract the route enforces:

  • pending_entries — uncompiled claims the next compile will process. Filter: claim_class='claim' AND compiled_at IS NULL AND not dismissed AND freshness_class IN ('current', 'aging') AND superseded_by IS NULL.
  • auto_promotable_evidence (v0.10.17+) — evidence rows the compiler's auto-promotion phase will promote AND that survive the post-promotion claim filter. Filter: claim_class='evidence' AND confidence >= 0.5 AND length(content) >= 30 AND not dismissed AND compiled_at IS NULL AND current/aging AND no superseder.
  • uncompiled_notes (v0.10.17+) — notes that need a bulk_promote call before they can compile.
  • compiled_entries, dismissed_entries, total_entries — straightforward counts.
  • stale_entries, low_confidence_entries, potentially_stale — review surfaces. potentially_stale uses the same compile-eligible predicate as pending_entries (notes / superseded claims with novel terms can't trigger a false-positive "Context may be stale" warning).
  • word_count — current compiled context size.
  • recommendations — strings driven by compile_work_total = pending_entries + auto_promotable_evidence. Notes-only fresh projects get "No compile-eligible entries yet — add claims (or promote evidence) before running compile" instead of a "compile to build context" pointer.

No parameters required.

Ask a question about the project. Gathers project context, searches the knowledge base, and finds related local sessions to assemble research material. Returns the assembled markdown plus a typed sources_cited list — [{type: "kb"|"session", id}] — resolved from a structured re-fetch of KB IDs and the local session search index, never regex-extracted from prose.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | question | string | yes | A question about the project |

Add a knowledge entry to the project knowledge base. Use when you discover patterns, decisions, conventions, bugs, or dependencies.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | content | string | yes | The knowledge entry text | | entry_type | string | yes | One of: decision, pattern, discovery, convention, bug, dependency | | session_id | string | no | Link this entry to a specific session | | confidence | number | no | Confidence score 0.0--1.0 (default: 1.0) |

Create or update a wiki page in the project knowledge base. Use for longer-form documentation of architecture, conventions, or concepts.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | slug | string | yes | URL-safe page identifier (e.g., architecture) | | content | string | yes | Full page content in markdown | | title | string | no | Page title (derived from slug if omitted) |

List all wiki pages for the project. Returns page slugs, titles, word counts, and entry counts. No parameters required.

Trigger a compile pass on the project's knowledge base. Promotes pending entries, refreshes section pages and concept pages, and rebuilds the compiled context document. Returns a structured result: entries_compiled, context_words_before, context_words_after, section_pages_updated, concept_pages_updated, compiled_at.

No parameters required.

Dismiss a knowledge entry that is stale, wrong, or no longer relevant. Idempotent — calling twice is a safe no-op. Writes a full audit triple (dismissed_at, dismissed_by, dismissed_reason) and the underlying PUT /entries/{id} is row-locked with SELECT FOR UPDATE so concurrent dismissals can't tear the audit record.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | id | number | yes | Knowledge entry ID | | reason | string | yes | Short justification (e.g., "superseded by entry 412" or "wrong file path") |

Returns the canonical project rules record plus compilation config for the current repo (static preferences, enabled tools, knowledge / context injection settings, tool overrides). Agents cannot modify rules through MCP — changes must go through sfs rules edit or the dashboard.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | git_remote | string | no | Override auto-detected git remote |

Returns the compiled rule text for a requested tool, or for the current tool if safely inferable. Useful when an agent needs to understand what behavior contract was materialized for its tool.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | tool | string | no | Tool slug: claude-code, codex, cursor, copilot, gemini | | git_remote | string | no | Override auto-detected git remote | | audit_session_id | string | no | Current session id to append this retrieval to its audit log |

Tier-gated by the agent_personas feature flag. Personas are portable AI roles per project — each persona has a name (^[A-Za-z0-9_-]{1,50}$), markdown content, and is project-scoped.

List all personas defined for the current project.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | git_remote | string | no | Git remote URL (auto-detected if omitted) |

Return a single persona's full content.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | name | string | yes | Persona name | | git_remote | string | no | Git remote URL (auto-detected if omitted) | | audit_session_id | string | no | Current session id to append this retrieval to its audit log |

Define a new persona for the project. Name must be unique within the project.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | name | string | yes | ASCII identifier, 1-50 chars | | content | string | yes | Markdown body | | git_remote | string | no | Git remote URL (auto-detected if omitted) |

Write a persona-only provenance bundle so the daemon tags subsequent captures with persona_name (and ticket_id=null).

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | name | string | yes | Persona name to assume | | git_remote | string | no | Git remote URL (auto-detected if omitted) |

Clear the active persona bundle. Refuses when a ticket-owned bundle is in effect — complete the ticket first.

No parameters required.

Tier-gated by the agent_tickets feature flag. Tickets are self-contained units of work with a server-enforced FSM (suggested → open → in_progress → blocked → review → done | cancelled), dependency graph (BFS cycle detection), comments, and an active-ticket provenance bundle.

Filter by status, assignee, or persona.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | status | string | no | One of the FSM states | | assignee | string | no | User ID | | persona | string | no | Persona name | | git_remote | string | no | Git remote URL (auto-detected if omitted) |

Return a ticket's full record, dependencies, dependents, and recent comments.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | ticket_id | string | yes | Ticket ID |

Open a new ticket. Agent-created tickets require ≥1 acceptance criterion + ≥20-char description; max 3 per session_id. Agent-source tickets land in suggested status — a human (or trusted agent) approves them with approve_ticket before they can be started.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | title | string | yes | Short summary | | description | string | yes | Markdown body | | acceptance_criteria | array | no | List of strings (required for agent source) | | depends_on | array | no | List of ticket IDs | | persona | string | no | Assign a persona | | git_remote | string | no | Git remote URL (auto-detected if omitted) |

Move a suggested ticket → open so it can be assigned and started. Returns 409 if the ticket is in any other state.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | ticket_id | string | yes | Ticket ID | | git_remote | string | no | Git remote URL (auto-detected if omitted) |

Atomic claim (UPDATE ... WHERE status='open' OR 'blocked' with rowcount guard). Increments and returns ticket.lease_epoch, creates a server-side retrieval_audit_id, writes both into the active-ticket bundle, and returns the compiled persona + ticket context (tool-aware token budget via tool).

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | ticket_id | string | yes | Ticket ID | | tool | string | no | claude-code (16k), codex/gemini/copilot/amp/generic (8k), cursor/windsurf/cline/roo-code/kilo-code (4k) | | force | boolean | no | Recover a blocked ticket; increments the lease epoch |

Send a ticket from in_progress to review and clear the owned bundle. Pass lease_epoch to reject stale workers with 409.

Lease fencing is opt-in for backward compatibility. The CLI and MCP start_ticket path write the current epoch into the active-ticket bundle, so normal ticket workers are fenced automatically. Callers that omit lease_epoch are treated as legacy/single-worker clients; this is coordinated audit fencing, not a strict mutex unless callers pass the epoch.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | ticket_id | string | yes | Ticket ID | | lease_epoch | integer | no | Optional stale-worker fence from start_ticket |

Move a ticket from review to done. Atomic with rowcount-1 guard. Pass lease_epoch to reject stale workers with 409.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | ticket_id | string | yes | Ticket ID | | lease_epoch | integer | no | Optional stale-worker fence from start_ticket |

Set the persona on a ticket.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | ticket_id | string | yes | Ticket ID | | persona | string | yes | Persona name |

Raise ticket priority and append a non-idempotent audit comment.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | ticket_id | string | yes | Ticket ID | | reason | string | yes | Why this is being escalated |

Slack-like comment thread. Non-idempotent (each call creates a row). Passing lease_epoch atomically rejects stale-worker comments when another worker has restarted the ticket; omitting it is allowed for legacy callers and is unfenced.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | ticket_id | string | yes | Ticket ID | | body | string | yes | Markdown body | | as_persona | string | no | Comment authored by this persona | | lease_epoch | integer | no | Optional stale-worker fence from start_ticket |

Local-only tools that operate on ~/.sessionfs. Use these to branch a session for "what-if" exploration or to mark a known-good state before risky changes. Neither tool uploads anything — call sfs push <new_id> afterwards if the fork should sync.

Create a named snapshot of a session's current manifest + messages under ~/.sessionfs/sessions/<id>.sfs/checkpoints/<name>/. Snapshot names must start with alphanumeric and use only [A-Za-z0-9._-] (1–100 chars). Re-using a name returns an error.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | session_id | string | yes | Full session id or unique prefix | | name | string | yes | Checkpoint name |

List checkpoints for a session, oldest first. Each entry returns name, created_at, message_count, and the on-disk path. Returns an empty list if there are no checkpoints.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | session_id | string | yes | Full session id or unique prefix |

Fork a session (or one of its checkpoints) into a new independent session. The new manifest records parent_session_id and — when from_checkpoint is supplied — forked_from_checkpoint, so lineage is introspectable.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | session_id | string | yes | Source session id or unique prefix | | name | string | yes | Title for the forked session | | from_checkpoint | string | no | Fork from this snapshot instead of the live head |

Handoffs are first-class coordination primitives. A handoff carries a session blob plus optional provenance (ticket_id + persona_name) and curated attachments (KB entries, wiki pages, ticket refs). On claim, the recipient's CLI persists an active_ticket_payload so the next captured session is automatically tagged with the handed-off context.

Three recipient kinds, exactly one per handoff: recipient_email (any user by email), recipient_user_id (direct account match), or recipient_team_id (Team+ tier; any team member can claim with atomic race protection).

Non-parties get 404 (not 403) on all handoff routes — existence-hiding so recipients can't distinguish pending vs claimed vs revoked. Pending handoffs past expires_at flip to expired on read; per-tier clamping is 720h (30d) on Free/Pro/Team, 2160h (90d) on Enterprise.

Create a handoff for a session. Sender provides exactly one recipient field plus optional ticket/persona provenance, expiry, and attachments.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | session_id | string | yes | Session being handed off | | recipient_email | string | no | Recipient email (one-of) | | recipient_user_id | string | no | Recipient user id (one-of) | | recipient_team_id | string | no | Recipient team id (one-of, Team+ tier) | | message | string | no | Optional sender note | | ticket_id | string | no | Attach an active ticket for provenance carry-through | | persona_name | string | no | Attach a persona for provenance carry-through | | expires_in_hours | integer | no | Clamped per tier (720h Free/Pro/Team, 2160h Enterprise) | | attachments | array | no | List of {kind: "kb_entry"\|"wiki_page"\|"ticket", ref_id} |

Atomic claim. UPDATE Handoff WHERE id=X AND status='pending' runs first; race losers never write blobs. Returns the new session_id, active_ticket_payload (if attached), and dropped_attachments for refs the recipient can't access.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | handoff_id | string | yes | Handoff ID |

Fetch one handoff. Non-parties get 404. First non-sender read stamps viewed_at and emits a viewed event.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | handoff_id | string | yes | Handoff ID |

List handoffs addressed to the caller (by email, user_id, or team membership). Optional status filter.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | status | string | no | pending, claimed, revoked, declined, expired | | limit | number | no | Page size |

List handoffs created by the caller. Optional status filter.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | status | string | no | Status filter | | limit | number | no | Page size |

Sender-only. Atomic revoke with a required reason. Emits revoked audit event and sends send_handoff_revoked email to the recipient.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | handoff_id | string | yes | Handoff ID | | reason | string | yes | Required revoke reason |

Recipient-only. Atomic decline with an optional reason. Emits declined audit event and sends send_handoff_declined email to the sender.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | handoff_id | string | yes | Handoff ID | | reason | string | no | Optional decline reason |

Append a comment to the handoff comment thread. Both parties (sender + valid recipients) can post; paged 200. Emits commented audit event and sends send_handoff_comment email to the other party.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | handoff_id | string | yes | Handoff ID | | body | string | yes | Markdown body |

Paginated read of the existing GET /api/v1/projects/{id}/tickets/{id}/comments endpoint. Returns markdown body, author, persona, and timestamps so MCP clients don't have to compose ticket-detail responses to inspect a comment thread.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | ticket_id | string | yes | Ticket ID | | limit | number | no | Page size (default: 50) | | cursor | string | no | Opaque pagination cursor |

Point an agent at a queue of tickets and wake it repeatedly — via /loop, cron, or CI — to service, review, and close them with SessionFS as the source of truth. The server holds all loop state, so the agent resumes correctly with no chat memory: each wake returns one bounded directive, and a crash between steps re-emits the same directive rather than losing or repeating work. Modes: review_until_clean (auto-finishes an item only on a server-verified, trusted, literal VERIFIED-CLEAN), implement_until_done, and triage. A built-in safety envelope (per-item attempt cap with 2m → 5m → 15m → 60m backoff that parks a stuck item for human reset, a per-wake ticket cap, a cadence floor, and a step rate limit) keeps an unattended loop bounded. These tools require the work_queues:read / work_queues:write scopes; acting on items also requires the relevant tickets / agent_runs write scopes. Available on all tiers. MCP / API only — there is no dashboard UI or CLI for work queues yet.

Create a queue over a ticket filter or explicit ticket list, with a mode, a cadence, and per-run / per-item budgets.

Return a queue's configuration and progress.

List the work queues for a project.

Pause, resume, or archive a queue.

Heartbeat: return one bounded directive (a single intent plus a small comment delta) for the agent to act on. Call this on each wake.

Report the result of the directive returned by run_work_queue_step. This is the only call that durably advances the queue.

When sfs mcp install runs, it injects a MANDATORY instructions block into the tool's project config file (e.g., CLAUDE.md, .cursorrules). These instructions tell the agent it must call add_knowledge() when discovering architecture decisions, code patterns, bugs, dependencies, or conventions — and must not end a session without contributing if it learned something new.

This creates a knowledge loop: each session reads project context at the start and writes back discoveries at the end. Tools that support project-level instructions: Claude Code (CLAUDE.md), Codex (codex.md), Gemini (GEMINI.md), Cursor (.cursorrules). For other tools, instructions are served at runtime via get_project_context.

For cloud-hosted agents (e.g., claude.ai) that cannot launch local processes, SessionFS supports HTTP/SSE transport with OAuth authentication. The remote server is deployed alongside the SessionFS API — agents connect via the SSE endpoint and authenticate using the same API key from sfs auth login. No separate service required.

| Variable | Description | |----------|-------------| | SFS_API_URL | SessionFS cloud API URL (for knowledge tools) | | SFS_API_KEY | API key for cloud authentication |

Terminal window
sfs mcp serve

Runs the MCP server on stdio transport. Connect from any MCP-compatible client.

Rebuild the search index:

Terminal window
sfs mcp index

Re-indexes all local sessions into the full-text search database.

Uninstall:

Terminal window
sfs mcp uninstall --for claude-code

Removes the MCP server registration and cleans up injected knowledge instructions from the project config file. Supported tools are the same as for install.