Documentation
¶
Overview ¶
Package filesystem implements the in-process built-in filesystem MCP.
The logic is extracted (not imported) from github.com/achetronic/filesystem-mcp internal/tools/*.go and adapted for direct use inside baifo:
- removed the dependency on github.com/mark3labs/mcp-go (tools are plain Go funcs wrapped as ADK tool.Tool via functiontool.New);
- removed RBAC / JWT plumbing (sandbox lives at the Builder level, and v1 grants every agent unrestricted access to its sandbox);
- merged write_file + append_file into a single tool with `encoding` and `mode` parameters to dodge LLM JSON-serialisation issues with long content (backticks, newlines, embedded JSON).
All side effects (undo state, scratch values, background processes) live in per-instance stores; constructing two Tools yields two independent universes, which lets isolated workers have their own.
Index ¶
- Constants
- type Config
- type DiffArgs
- type DiffResult
- type EditFileArgs
- type EditFileResult
- type EditOpResult
- type EditOperation
- type ExecArgs
- type ExecResult
- type LsArgs
- type LsEntry
- type LsResult
- type ProcessEntry
- type ProcessKillArgs
- type ProcessKillResult
- type ProcessStatusArgs
- type ProcessStatusResult
- type ReadFileArgs
- type ReadFileResult
- type ReadFragment
- type ReadRange
- type ScratchArgs
- type ScratchResult
- type SearchArgs
- type SearchMatch
- type SearchResult
- type SystemInfoResult
- type Tools
- func (t *Tools) ADKTools() ([]tool.Tool, error)
- func (t *Tools) Diff(args DiffArgs) (DiffResult, error)
- func (t *Tools) EditFile(args EditFileArgs) (EditFileResult, error)
- func (t *Tools) Exec(args ExecArgs) (ExecResult, error)
- func (t *Tools) Ls(args LsArgs) (LsResult, error)
- func (t *Tools) ProcessKill(args ProcessKillArgs) (ProcessKillResult, error)
- func (t *Tools) ProcessStatus(args ProcessStatusArgs) (ProcessStatusResult, error)
- func (t *Tools) ReadFile(args ReadFileArgs) (ReadFileResult, error)
- func (t *Tools) Scratch(args ScratchArgs) (ScratchResult, error)
- func (t *Tools) Search(args SearchArgs) (SearchResult, error)
- func (t *Tools) SystemInfo() (SystemInfoResult, error)
- func (t *Tools) Undo(args UndoArgs) (UndoResult, error)
- func (t *Tools) WriteFile(args WriteFileArgs) (WriteFileResult, error)
- type UndoArgs
- type UndoResult
- type WriteFileArgs
- type WriteFileResult
Constants ¶
const ( ScratchSet = "set" ScratchGet = "get" ScratchDelete = "delete" ScratchList = "list" )
Supported actions for ScratchArgs.Action.
const ( EncodingUTF8 = "utf-8" EncodingBase64 = "base64" )
Supported values for WriteFileArgs.Encoding.
const ( WriteModeOverwrite = "overwrite" WriteModeAppend = "append" )
Supported values for WriteFileArgs.Mode.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Config ¶
type Config struct {
// Logger is used for non-fatal errors (e.g. failure to record undo
// state). Defaults to slog.Default() when nil.
Logger *slog.Logger
// MaxExecOutputChars caps stdout/stderr (each) returned by exec and
// process_status. 0 means unlimited.
MaxExecOutputChars int
// MaxReadFileChars caps the total characters returned by one
// read_file call. 0 means unlimited.
MaxReadFileChars int
// MaxSearchOutputChars caps the total characters (matched lines plus
// their context) returned by one search call. 0 means unlimited.
MaxSearchOutputChars int
}
Config bundles construction-time options.
type DiffArgs ¶
type DiffArgs struct {
PathA string `json:"path_a"`
PathB string `json:"path_b"`
StartA int `json:"start_a,omitempty"`
EndA int `json:"end_a,omitempty"`
StartB int `json:"start_b,omitempty"`
EndB int `json:"end_b,omitempty"`
}
DiffArgs is the input of the Diff tool.
type DiffResult ¶
type DiffResult struct {
PathA string `json:"path_a"`
PathB string `json:"path_b"`
Identical bool `json:"identical"`
Unified string `json:"unified,omitempty"`
}
DiffResult is what the LLM receives.
type EditFileArgs ¶
type EditFileArgs struct {
Path string `json:"path"`
Edits []EditOperation `json:"edits"`
}
EditFileArgs is the input of the EditFile tool.
type EditFileResult ¶
type EditFileResult struct {
Path string `json:"path"`
EditsApplied int `json:"edits_applied"`
EditsFailed int `json:"edits_failed"`
Results []EditOpResult `json:"results"`
}
EditFileResult is what the LLM receives.
type EditOpResult ¶
type EditOpResult struct {
Index int `json:"index"`
Success bool `json:"success"`
Error string `json:"error,omitempty"`
}
EditOpResult reports the outcome of one EditOperation.
type EditOperation ¶
type EditOperation struct {
OldText string `json:"old_text"`
NewText string `json:"new_text"`
ReplaceAll bool `json:"replace_all,omitempty"`
}
EditOperation is one find-and-replace operation.
type ExecArgs ¶
type ExecArgs struct {
Command string `json:"command"`
Workdir string `json:"workdir,omitempty"`
Timeout int `json:"timeout,omitempty"`
Env map[string]string `json:"env,omitempty"`
Background bool `json:"background,omitempty"`
}
ExecArgs is the input of the Exec tool.
type ExecResult ¶
type ExecResult struct {
ProcessID string `json:"process_id,omitempty"`
ExitCode int `json:"exit_code"`
Stdout string `json:"stdout"`
Stderr string `json:"stderr"`
StdoutTruncated bool `json:"stdout_truncated,omitempty"`
StderrTruncated bool `json:"stderr_truncated,omitempty"`
}
ExecResult is what the LLM receives. ProcessID is set only when Background=true; the other fields apply to the synchronous case.
type LsArgs ¶
type LsArgs struct {
Path string `json:"path"`
Depth int `json:"depth,omitempty"`
Pattern string `json:"pattern,omitempty"`
IncludeHidden bool `json:"include_hidden,omitempty"`
}
LsArgs is the input of the Ls tool.
type LsEntry ¶
type LsEntry struct {
Name string `json:"name"`
Path string `json:"path"`
Type string `json:"type"`
Depth int `json:"depth"`
Size int64 `json:"size,omitempty"`
Mode string `json:"mode"`
ModTime string `json:"mod_time"`
}
LsEntry mirrors a filesystem entry returned by Ls. Output is flat (no nested children) so the schema inference works and the LLM gets a simpler shape to reason about. Tree structure is conveyed by the Depth field plus the lexicographic order of paths.
type LsResult ¶
type LsResult struct {
Entries []LsEntry `json:"entries"`
}
LsResult is what the LLM receives.
type ProcessEntry ¶
type ProcessEntry struct {
ID string `json:"id"`
Command string `json:"command"`
WorkDir string `json:"workdir,omitempty"`
StartedAt string `json:"started_at"`
Done bool `json:"done"`
ExitCode int `json:"exit_code"`
Stdout string `json:"stdout,omitempty"`
Stderr string `json:"stderr,omitempty"`
StdoutTruncated bool `json:"stdout_truncated,omitempty"`
StderrTruncated bool `json:"stderr_truncated,omitempty"`
}
ProcessEntry is a snapshot of one background process.
type ProcessKillArgs ¶
type ProcessKillArgs struct {
ID string `json:"id"`
}
ProcessKillArgs is the input of the ProcessKill tool.
type ProcessKillResult ¶
type ProcessKillResult struct {
ID string `json:"id"`
}
ProcessKillResult is what the LLM receives.
type ProcessStatusArgs ¶
type ProcessStatusArgs struct {
ID string `json:"id,omitempty"`
}
ProcessStatusArgs is the input of the ProcessStatus tool. An empty ID lists every background process.
type ProcessStatusResult ¶
type ProcessStatusResult struct {
Processes []ProcessEntry `json:"processes"`
Total int `json:"total"`
}
ProcessStatusResult is what the LLM receives.
type ReadFileArgs ¶
ReadFileArgs is the input of the ReadFile tool.
type ReadFileResult ¶
type ReadFileResult struct {
Path string `json:"path"`
TotalLines int `json:"total_lines"`
Fragments []ReadFragment `json:"fragments"`
Truncated bool `json:"truncated,omitempty"`
TruncationNote string `json:"truncation_note,omitempty"`
}
ReadFileResult is what the LLM receives.
type ReadFragment ¶
type ReadFragment struct {
Offset int `json:"offset"`
Limit int `json:"limit"`
Lines []string `json:"lines"`
TotalLines int `json:"total_lines"`
}
ReadFragment is a slice of lines, numbered for the LLM's benefit.
type ScratchArgs ¶
type ScratchArgs struct {
Action string `json:"action"`
Key string `json:"key,omitempty"`
Value string `json:"value,omitempty"`
}
ScratchArgs is the input of the Scratch tool. Key/Value semantics depend on Action; documented per case below.
type ScratchResult ¶
type ScratchResult struct {
Value string `json:"value,omitempty"`
Items map[string]string `json:"items,omitempty"`
Action string `json:"action"`
Key string `json:"key,omitempty"`
}
ScratchResult is what the LLM receives. Different fields are filled depending on the action.
type SearchArgs ¶
type SearchArgs struct {
Pattern string `json:"pattern"`
Path string `json:"path"`
Include string `json:"include,omitempty"`
Exclude string `json:"exclude,omitempty"`
Literal bool `json:"literal,omitempty"`
ContextLines int `json:"context_lines,omitempty"`
MaxResults int `json:"max_results,omitempty"`
}
SearchArgs is the input of the Search tool.
type SearchMatch ¶
type SearchMatch struct {
File string `json:"file"`
Line int `json:"line"`
Content string `json:"content"`
ContextBefore []string `json:"context_before,omitempty"`
ContextAfter []string `json:"context_after,omitempty"`
}
SearchMatch is one hit returned by Search.
type SearchResult ¶
type SearchResult struct {
Matches []SearchMatch `json:"matches"`
TotalMatches int `json:"total_matches"`
Truncated bool `json:"truncated"`
TruncationNote string `json:"truncation_note,omitempty"`
}
SearchResult is what the LLM receives.
type SystemInfoResult ¶
type SystemInfoResult struct {
OS string `json:"os"`
Architecture string `json:"arch"`
Hostname string `json:"hostname"`
User string `json:"user"`
WorkingDir string `json:"workdir"`
NumCPU int `json:"num_cpu"`
Time time.Time `json:"time"`
}
SystemInfoResult is what the LLM receives.
type Tools ¶
type Tools struct {
// contains filtered or unexported fields
}
Tools is the entry point of the built-in filesystem MCP. It owns the per-instance mutable state (undo, scratch, processes) and exposes methods that match the MCP tool surface one-to-one.
Methods are designed to be called via functiontool.New, but they are also usable directly from Go code (e.g. tests, internal scripting).
func (*Tools) ADKTools ¶
ADKTools returns every tool of the built-in filesystem MCP wrapped as a google.golang.org/adk tool.Tool. The names match the original filesystem-mcp tool names so existing prompts keep working.
Each tool description targets the LLM and documents quirks the model needs to know — especially the encoding/mode parameters of write_file that were added to dodge JSON tool-call corruption with long content.
func (*Tools) Diff ¶
func (t *Tools) Diff(args DiffArgs) (DiffResult, error)
Diff returns a unified-style diff between path_a and path_b (or slices of them when start/end are given). Implementation is an LCS table, which is fine for files up to a few thousand lines.
func (*Tools) EditFile ¶
func (t *Tools) EditFile(args EditFileArgs) (EditFileResult, error)
EditFile applies a list of find-and-replace operations to a file. Edits are applied sequentially against the running content; an operation fails if old_text is missing or matches multiple times without replace_all=true. All-or-nothing semantics would be safer but harder to debug, so we surface per-operation results instead.
func (*Tools) Exec ¶
func (t *Tools) Exec(args ExecArgs) (ExecResult, error)
Exec runs a shell command in the foreground (with a timeout) or in the background (returning a process_id that subsequent tools can inspect). Workdir is sanitised through resolvePath if set.
func (*Tools) Ls ¶
Ls lists directory contents up to args.Depth (default 1). Hidden entries are filtered out unless IncludeHidden is set. The Pattern is matched against file names (directories are always shown so the tree can be walked).
func (*Tools) ProcessKill ¶
func (t *Tools) ProcessKill(args ProcessKillArgs) (ProcessKillResult, error)
ProcessKill terminates a background process. The OS Kill signal is sent; the process may take a moment to actually exit.
func (*Tools) ProcessStatus ¶
func (t *Tools) ProcessStatus(args ProcessStatusArgs) (ProcessStatusResult, error)
ProcessStatus returns the status of one or every background process.
func (*Tools) ReadFile ¶
func (t *Tools) ReadFile(args ReadFileArgs) (ReadFileResult, error)
ReadFile reads a file in full or in ranges. Ranges are 0-based and each fragment is returned with line numbers prefixed so the LLM can reference them precisely without re-counting.
When t.maxReadFileChars is non-zero, a character budget is maintained across all fragments. Once the budget is exhausted the current fragment's Limit is adjusted to the lines actually included, remaining ranges are dropped, and the result carries Truncated=true together with a TruncationNote that tells the model how to read the rest. Truncation happens at whole-line granularity, with one exception: when the very first line already exceeds the budget (single-huge-line files), its head is returned with an inline truncation marker so the result is never empty.
func (*Tools) Scratch ¶
func (t *Tools) Scratch(args ScratchArgs) (ScratchResult, error)
Scratch is a multiplexed tool for the four actions of a small KV store. The original filesystem-mcp shipped it as one tool with an `action` discriminator; we keep that shape for compatibility.
func (*Tools) Search ¶
func (t *Tools) Search(args SearchArgs) (SearchResult, error)
Search walks the path tree and returns every line matching the regex. Literal=true escapes the pattern so the LLM can search for raw strings without learning regex syntax.
Two independent limits bound the result. max_results caps the number of matches (default 100). When t.maxSearchOutputChars is non-zero, a character budget caps the total size of the matched lines and their context across all files: once a match would push the result past the budget it is dropped (at whole-match granularity, so a match is never split), remaining files are skipped, and the result carries Truncated=true with a TruncationNote telling the model how to narrow the query. The char budget is what keeps a broad pattern from flooding the context window even when it stays under max_results.
func (*Tools) SystemInfo ¶
func (t *Tools) SystemInfo() (SystemInfoResult, error)
SystemInfo collects coarse environment info. The LLM is told via the tool description to call this ONLY on explicit user request; preemptive calls just spam the chat with system facts the user did not ask for.
func (*Tools) Undo ¶
func (t *Tools) Undo(args UndoArgs) (UndoResult, error)
Undo reverts the last write_file or edit_file operation on path.
func (*Tools) WriteFile ¶
func (t *Tools) WriteFile(args WriteFileArgs) (WriteFileResult, error)
WriteFile creates, overwrites or appends to a file. The previous content (if any) is snapshotted into the undo store before the write so the change can be reverted.
type UndoArgs ¶
type UndoArgs struct {
Path string `json:"path"`
}
UndoArgs is the input of the Undo tool.
type UndoResult ¶
type UndoResult struct {
Path string `json:"path"`
}
UndoResult is what the LLM receives.
type WriteFileArgs ¶
type WriteFileArgs struct {
Path string `json:"path"`
Content string `json:"content"`
Encoding string `json:"encoding,omitempty"`
Mode string `json:"mode,omitempty"`
}
WriteFileArgs is the input of the WriteFile tool.
Two extra knobs vs the original filesystem-mcp version:
- Encoding lets the LLM submit content as base64 to dodge JSON serialisation issues with backticks, newlines and embedded JSON. The model seems to truncate / corrupt long literal strings in tool-call payloads more often than long base64 strings.
- Mode lets the LLM grow a file incrementally without having to fetch the previous content (which would require an extra read_file turn).
type WriteFileResult ¶
type WriteFileResult struct {
Path string `json:"path"`
BytesWritten int `json:"bytes_written"`
Mode string `json:"mode"`
}
WriteFileResult is what the LLM receives.