{
  "markdown": "<div align=\"center\">\n\n# 🐙 Octofs\n\n**Give your AI assistant filesystem superpowers**\n\n[![CI](https://github.com/muvon/octofs/actions/workflows/ci.yml/badge.svg)](https://github.com/muvon/octofs/actions/workflows/ci.yml)\n[![Coverage](https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Fmuvon%2Foctofs%2Fbadges%2Fcoverage.json&style=flat-square)](https://github.com/muvon/octofs/actions/workflows/ci.yml)\n[![Rust](https://img.shields.io/badge/Rust-1.95+-orange.svg?logo=rust)](https://www.rust-lang.org)\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)\n[![MCP](https://img.shields.io/badge/MCP-2026--07--28-green.svg)](https://modelcontextprotocol.io)\n[![Version](https://img.shields.io/crates/v/octofs.svg)](https://crates.io/crates/octofs)\n\n*Standalone Rust binary that exposes filesystem tools over the Model Context Protocol. Built on `rmcp` 3.x, `tokio`, and `axum`.*\n\n[Installation](#installation) · [Quick Start](#quick-start) · [Features](#features) · [Tools Reference](#mcp-tools-reference) · [Architecture](#architecture) · [Changelog](CHANGELOG.md)\n\nMCP Registry: [`io.github.Muvon/octofs`](https://registry.modelcontextprotocol.io)\n\n</div>\n\n---\n\n## Why Octofs?\n\nYour AI coding assistant (Cursor, Claude, Windsurf, etc.) is smart — but it's **blind to your filesystem**. Octofs bridges that gap, giving your AI:\n\n- **Eyes** — Read files, search content, explore directories\n- **Hands** — Create, edit, batch-modify files atomically\n- **Context** — Execute commands, manage working directories\n- **Reach** — Transparent SSH/SFTP: every file tool accepts `ssh://` URLs\n\n```\n┌─────────────────────────────────────────────────────────────┐\n│  You: \"Refactor all error handling to use anyhow::Context\" │\n├─────────────────────────────────────────────────────────────┤\n│  AI without Octofs:                                         │\n│  • \"I can't see your project structure\"                     │\n│  • \"Please paste the relevant files\"                        │\n│  • *Wastes 10 minutes on back-and-forth*                    │\n├─────────────────────────────────────────────────────────────┤\n│  AI with Octofs:                                            │\n│  • Reads your codebase directly                             │\n│  • Finds all error handling patterns                         │\n│  • Suggests atomic batch edits                              │\n│  • Applies changes with your approval                       │\n└─────────────────────────────────────────────────────────────┘\n```\n\n## What Makes It Different\n\n| Feature | Octofs | Typical Alternatives |\n|---------|--------|---------------------|\n| **Implementation** | Compiled Rust binary, no runtime | Python/Node script |\n| **Content Search** | Built-in search with context lines | String matching only |\n| **Batch Operations** | Atomic multi-edit on single file | One-at-a-time |\n| **Line Addressing** | Composite `N:hh` ids — hash-verified at apply time; stale edits fail with relocation hints | Number-only |\n| **Transport** | STDIO + Streamable HTTP | STDIO only |\n| **Shell Integration** | Automatic foreground-to-background handoff | Limited or none |\n| **Remote Files** | Transparent SSH/SFTP on every file tool | None |\n| **Re-reads** | Delta views — re-viewing a file returns only the hunks changed since | Full file every time |\n| **Safety** | Gitignore-aware, stale-write detection, path validation | Full filesystem access |\n\n---\n\n## Installation\n\n### Cargo (crates.io)\n\n```bash\ncargo install octofs\n```\n\n### Homebrew\n\n```bash\nbrew install muvon/tap/octofs\n```\n\n### npm (no Rust toolchain needed)\n\n```bash\nnpx -y @muvon/octofs --version\n```\n\nThe wrapper downloads the matching pre-built binary on first run. MCP config:\n\n```json\n{\n  \"mcpServers\": {\n    \"octofs\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@muvon/octofs\", \"mcp\"]\n    }\n  }\n}\n```\n\n### Pre-built Binaries\n\nDownload from [GitHub Releases](https://github.com/muvon/octofs/releases) for your platform:\n\n| Platform | Target |\n|----------|--------|\n| Linux (x86_64) | `x86_64-unknown-linux-musl` |\n| Linux (ARM64) | `aarch64-unknown-linux-musl` |\n| Windows (x86_64) | `x86_64-pc-windows-msvc` |\n| Windows (ARM64) | `aarch64-pc-windows-msvc` |\n| macOS (Intel) | `x86_64-apple-darwin` |\n| macOS (Apple Silicon) | `aarch64-apple-darwin` |\n\nEach release also ships `.mcpb` bundles for one-click install in clients that support MCP bundles (e.g. Claude Desktop).\n\n### MCP Registry\n\nPublished to the [MCP Registry](https://registry.modelcontextprotocol.io) as `io.github.Muvon/octofs`.\n\n### From Source\n\nRequires Rust 1.95+.\n\n```bash\ngit clone https://github.com/muvon/octofs\ncd octofs\ncargo build --release\n# Binary at ./target/release/octofs\n```\n\n---\n\n## Quick Start\n\n### 1. Configure Your AI Assistant\n\nThe CLI uses a `mcp` subcommand — your config must pass `[\"mcp\"]` as args.\n\n**Cursor** (`~/.cursor/mcp.json`):\n```json\n{\n  \"mcpServers\": {\n    \"octofs\": {\n      \"command\": \"octofs\",\n      \"args\": [\"mcp\"]\n    }\n  }\n}\n```\n\n**Claude Desktop** (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):\n```json\n{\n  \"mcpServers\": {\n    \"octofs\": {\n      \"command\": \"octofs\",\n      \"args\": [\"mcp\"]\n    }\n  }\n}\n```\n\n**Windsurf** (`~/.windsurf/mcp.json`):\n```json\n{\n  \"mcpServers\": {\n    \"octofs\": {\n      \"command\": \"octofs\",\n      \"args\": [\"mcp\"]\n    }\n  }\n}\n```\n\n> If Octofs isn't on your `PATH`, use the full path to the binary (e.g. `/usr/local/bin/octofs` or `./target/release/octofs`).\n\n### 2. Restart Your AI Assistant\n\nThe MCP server starts automatically when your AI assistant connects.\n\n### 3. Try It\n\nAsk your AI assistant to:\n- \"Show me the project structure\"\n- \"Read the main.rs file\"\n- \"Search for all uses of `unwrap()` in the codebase\"\n- \"Create a new file called `test.rs`\"\n\n---\n\n## Features\n\n### 📁 Filesystem Operations\n\n- **View Files & Directories** — Read a single file (call `view` in parallel for several), list directories with glob patterns, search content\n- **Smart Truncation** — Large files are truncated intelligently to avoid overwhelming context windows\n- **Gitignore-Aware** — Respects `.gitignore` patterns during directory traversal\n- **Line Ranges** — Read specific line ranges with negative indexing (`-1` = last line)\n- **Remote Files (SSH/SFTP)** — Every file tool accepts `ssh://user@host:port/path` URLs (see [Remote Filesystem](#remote-filesystem-sshsftp))\n\n### ✏️ Text Editing\n\n- **Create Files** — Create new files with automatic parent directory creation\n- **String Replace** — Replace exact string matches with fuzzy fallback for whitespace\n- **Delete** — Remove a file (recoverable via undo)\n- **Undo** — Revert last edit (up to 10 undo levels per file, in-memory)\n- **Batch Edit** — Perform multiple insert/replace operations atomically on a single file\n- **Stale-Write Protection** — Every edit target's `N:hh` id is verified against the file at apply time; a stale id fails with the current content and where it moved, instead of editing the wrong line\n\n### 🔍 Code Intelligence\n\n- **Content Search** — Search for strings within files with context lines\n- **Line Extraction** — Copy specific line ranges from one file to another\n\n### 🖥️ Shell & System\n\n- **Command Execution** — Run shell commands with output capture\n- **Background Processes** — Long commands automatically continue in background with completion notifications\n- **Working Directory** — Set/get/reset working directory context for operations\n\n---\n\n## Configuration\n\n### Line Identifiers\n\nEvery line is addressed by a composite id `N:hh` — its 1-indexed position plus a\n2-character hex hash (FNV-1a) of its content. `view` renders lines as `N:hh|content`:\n\n```\n1:a3|fn main() {\n2:f1|    println!(\"Hello\");\n3:0e|}\n```\n\nEdit tools take these ids back as targets and verify the hash against the file\nbefore applying anything. A stale id (the file changed since it was viewed) fails\nwith the current content around the target and where the expected content moved —\nso the model retargets from the error instead of re-reading the file. Edit results\nare diffs with fresh ids, so edits chain without re-viewing. Removed lines collapse\nto their old id range (`-12:a3..15:f1 (4 lines)`), and a trailing\n`shift: lines after 40:b2 +3` line says how original line numbers below each edit\nmoved, so ids the model still holds can be adjusted without a failed call.\n\nThis is the single line-id format — there is no mode switch. Plain line numbers\nare still accepted where a position alone is safe: `view` ranges (negative counts\nfrom the end) and the insert anchors `0` (file start) / `-1` (append).\n\n### Shell Misuse Enforcement\n\nOctofs detects shell misuse — commands like `cat`, `grep`, `find`, or `sed` that\nshould use the dedicated MCP tools instead — and rejects them with an error\nexplaining which tool to use. The call fails; nothing executes. This is\nintentional and not configurable: the dedicated tools give the model line ids,\ngitignore-awareness, and remote-host support that raw shell output cannot.\nPipelines (`cargo build 2>&1 | grep error`) remain allowed — only standalone\ninvocations of those programs are blocked.\n\nOther guidance (out-of-bounds ranges, fuzzy-match notices) is appended to\nsuccessful responses as ⚠️ hints without failing the call.\n\n### Transport Modes\n\n#### STDIO (default)\n\nStandard input/output transport. Works with all MCP clients.\n\n```bash\noctofs mcp\n```\n\n#### HTTP\n\nStreamable HTTP transport for remote access or multi-client scenarios.\n\n```bash\noctofs mcp --bind 0.0.0.0:12345\n```\n\nConnect clients to `http://localhost:12345/mcp`.\n\n### Working Directory\n\nBy default, Octofs operates in the current directory. Specify a different root:\n\n```json\n{\n  \"mcpServers\": {\n    \"octofs\": {\n      \"command\": \"octofs\",\n      \"args\": [\"mcp\", \"--path\", \"/path/to/your/project\"]\n    }\n  }\n}\n```\n\n### Remote Filesystem (SSH/SFTP)\n\nAll path parameters — and `--path` itself — accept `ssh://` or `sftp://` URLs:\n\n```bash\n# Remote session root: relative paths resolve on the remote host\noctofs mcp --path ssh://deploy@example.com/var/www/app --ssh-key ~/.ssh/id_ed25519\n```\n\n```\nview path=\"ssh://deploy@example.com/etc/nginx/nginx.conf\"\n```\n\n- **Login home** — `ssh://host` (no path) and `ssh://host/~/dir` resolve against the login user's home, like `ssh host` / `scp host:dir`. `ssh://host/dir` stays absolute.\n- **OpenSSH config** — host aliases are resolved through the local OpenSSH config (including `Include` and `Match`) and honor `HostName`, `User`, `Port`, and a single `ProxyJump`. Explicit URL values win, so both `ssh://dev/path` and `ssh://user@example.com:2222/path` work as expected. Multi-hop `ProxyJump` and `ProxyCommand` routing are rejected with a clear error.\n- **Authentication** — uses the host's `IdentityAgent` (e.g. 1Password) or `$SSH_AUTH_SOCK`, then key files — `--ssh-key` if given, the host's `IdentityFile` entries, then the defaults in `~/.ssh` (`id_ed25519`, `id_ecdsa`). Passphrase-protected key files are not supported directly; use an agent instead.\n- **RSA keys are not supported** — the Rust `rsa` crate has an unfixed timing side-channel (Marvin attack, [RUSTSEC-2023-0071](https://rustsec.org/advisories/RUSTSEC-2023-0071)), so octofs is built without RSA entirely. Use an ed25519 key instead (`ssh-keygen -t ed25519`); ecdsa also works. RSA-only setups fail with a clear error naming the key.\n- **Host keys** — verified against `~/.ssh/known_hosts` with the OpenSSH `accept-new` policy: unknown hosts are recorded on first use, a changed key fails closed.\n- **`--ssh-timeout SECS`** — connection timeout (default 30). Connections are pooled per host, kept alive with transport keepalives, and reconnected automatically if they drop.\n- **`shell` stays local** — commands always run on the machine where Octofs runs; only file tools (`view`, `text_editor`, `batch_edit`, `extract_lines`, `workdir`) reach remote hosts.\n\n---\n\n## MCP Tools Reference\n\n### `view` — Read files, list directories, search content\n\n**File reading:** (`path` is a single path; `start`/`end` are line numbers or line ids)\n```json\n{\"path\": \"src/main.rs\"}                          // whole file\n{\"path\": \"src/main.rs\", \"start\": 10, \"end\": 20}  // lines 10–20\n{\"path\": \"src/main.rs\", \"start\": 42, \"end\": 42}  // single line\n{\"path\": \"src/main.rs\", \"start\": 80}             // line 80 → end of file\n{\"path\": \"src/main.rs\", \"start\": -20}            // last 20 lines\n{\"path\": \"src/main.rs\", \"start\": \"12:a3\", \"end\": \"20:f1\"}  // line ids from prior output\n```\n\nOutput renders every line as `N:hh|content` — the `N:hh` prefix is the line id\nthat `batch_edit` and `extract_lines` take as targets.\n\nTo read several files, make multiple `view` calls — they run in parallel.\n\nReuse content and line ids already returned. Read a complete relevant function or block\nin one call, combining adjacent windows. If its location is unknown, use `content` with\nenough `context` to understand the matches, then fetch only missing surrounding code.\nDo not re-read overlapping ranges or repeatedly narrow a range just to pick edit targets.\nRe-read when the file may have changed, output was truncated, or prior context is unavailable.\nEmpty files return `[empty file, 0 lines]` on an initial or forced full read.\n\n**Delta views:** a whole-file view of a file the session already served returns\nonly the hunks changed since — the same `...`/`-`/`+` style as edit results, with\nremoved lines collapsed to their old id range — or\n`[unchanged since you last viewed or edited it: N lines. Pass full: true to re-read.]`.\nOctofs' own edits keep the cache current, so a re-view after your own `batch_edit`\ncosts one line. Ranged views and content search always render exactly what was asked.\n`full` has no effect on ranges or searches; omit `start`/`end` and content search to\nforce a complete file read. It does not change output limits.\n```json\n{\"path\": \"src/main.rs\", \"full\": true}   // force the complete file (e.g. after context compaction)\n```\n\n**Directory listing:**\n```json\n{\"path\": \"src/\"}\n{\"path\": \"src/\", \"pattern\": \"*.rs\"}\n{\"path\": \"src/\", \"max_depth\": 2, \"include_hidden\": true}\n```\n\nA bare listing of a remote directory (`ssh://host/path`, no `pattern`/`content`)\ndefaults to `max_depth: 1` — root entries only — because every subdirectory costs\nan SFTP round trip; pass `max_depth` explicitly to walk deeper. Searches with\n`pattern` or `content` always walk the whole tree, like `rg`.\n\n`pattern` uses the same gitignore-style glob grammar as ripgrep's `-g/--glob`:\nwithout `/` it matches filenames at any depth, while a pattern containing `/`\nmatches the returned relative path. It supports `*` within one path component,\n`**` across directories, `?`, character classes such as `[abc]`, brace alternatives\nsuch as `*.{rs,toml}`, and leading `!` exclusions. Use `|` to pass ordered globs in\none MCP string; later globs take precedence:\n\n```json\n{\"path\": \".\", \"pattern\": \"**/*.{rs,toml}|!target/**\"}\n{\"path\": \".\", \"content\": \"unsafe\", \"pattern\": \"src/**/*.rs|!src/generated/**\"}\n```\n\nThe glob filters files discovered by Octofs' gitignore-aware traversal. Use\n`include_hidden: true` to include hidden paths; gitignored paths remain excluded.\nPatterns are limited to 4096 UTF-8 bytes, 64 `|`-separated rules, and 16 nested\nbrace levels. They must be a single line and are validated before traversal.\nEscape a literal leading `#` or `!` as `\\#` or `\\!`; otherwise `#` is rejected\ninstead of silently acting as a gitignore comment. Empty brace alternatives such\nas `{,rs}` are rejected because ripgrep does not support them.\n\n**Content search:** (literal by default; set `regex: true` for a Rust regex, `(?i)` = case-insensitive)\n```json\n{\"path\": \"src\", \"content\": \"fn main\"}\n{\"path\": \"src\", \"content\": \"unwrap()\", \"context\": 3}\n{\"path\": \"src\", \"content\": \"(?i)error\", \"regex\": true}\n{\"path\": \"docs|scripts|BENCHMARK.md\", \"content\": \"update_benchmark.py\", \"context\": 4}\n```\n\nFor an rg-style search across several roots, `path` accepts `|`-separated literal\nfiles and directories when `content` is set. The roots are not regexes: as with\nrg's positional path arguments, each one must exist. A real path containing `|`\ntakes precedence over this shorthand. Root lists must be single-line, contain no\nduplicates, and are limited to 32 roots and 8192 UTF-8 bytes.\n\nDirectory listings annotate each file as `path<TAB>NL<TAB>~Nt` (line count + estimated tokens) so you can budget reads before opening files; binary files show `path<TAB>(binary)`.\n\n---\n\n### `text_editor` — Create, edit, replace text\n\n**Create file:**\n```json\n{\"command\": \"create\", \"path\": \"src/new.rs\", \"content\": \"pub fn new() {}\"}\n```\n\n**Replace string:** (`old_text` must match exactly once)\n```json\n{\n  \"command\": \"str_replace\",\n  \"path\": \"src/main.rs\",\n  \"old_text\": \"fn old()\",\n  \"new_text\": \"fn new()\"\n}\n```\n\n**Replace ALL occurrences** (rename-style edits):\n```json\n{\n  \"command\": \"str_replace\",\n  \"path\": \"src/main.rs\",\n  \"old_text\": \"old_name\",\n  \"new_text\": \"new_name\",\n  \"replace_all\": true\n}\n```\n\nMatching is progressive: exact → escaped-literal recovery (double-escaped `\\n`/`\\t`\ninterpreted when the result matches uniquely) → whitespace-normalized fuzzy with\nindentation adjustment → rich diagnostics with the closest candidates and their\nline ids. CRLF files are matched in LF space and keep their line endings on write.\n\n**Delete file:** (recoverable with `undo_edit`)\n```json\n{\"command\": \"delete\", \"path\": \"src/old.rs\"}\n```\n\n**Undo last edit:**\n```json\n{\"command\": \"undo_edit\", \"path\": \"src/main.rs\"}\n```\n\n---\n\n### `batch_edit` — Atomic multi-operation edits\n\nPerform multiple insert/replace operations on a single file atomically.\n\nEach operation has a `start`. For `replace` it's the first line of the range as a\nline id copied from `view` output (add `end` for a range; omit it for a single\nline). For `insert` it's the anchor to insert after — a line id, or the integers\n`0` (file start) / `-1` (after last line). Every id is verified against the file\nbefore anything applies; a stale id fails with the current content so the model\ncan retarget without a re-view. The result is a diff with fresh ids.\n\n**Insert at beginning:**\n```json\n{\n  \"path\": \"src/main.rs\",\n  \"operations\": [\n    {\"operation\": \"insert\", \"start\": 0, \"content\": \"// Header\\n\"}\n  ]\n}\n```\n\n**Replace lines:**\n```json\n{\n  \"path\": \"src/main.rs\",\n  \"operations\": [\n    {\"operation\": \"replace\", \"start\": \"10:4b\", \"end\": \"15:c2\", \"content\": \"new code here\"}\n  ]\n}\n```\n\n---\n\n### `extract_lines` — Copy lines between files\n\n```json\n{\n  \"from_path\": \"src/utils.rs\",\n  \"from_start\": 10,\n  \"from_end\": 25,\n  \"append_path\": \"src/new.rs\",\n  \"append_line\": -1\n}\n```\n\n`from_end` is optional (omit to copy a single line). `from_start`, `from_end`, and\n`append_line` each accept a line number or a line id (`\"12:a3\"`, verified against\nthe file). `append_line` positions the copy in the target: `0` = beginning,\n`-1` = end, `N` = after line N.\n\n---\n\n### `shell` — Execute commands\n\nCommands start in the foreground and return their output normally when they\nfinish within about 10 seconds:\n\n```json\n{\"command\": \"cargo test\"}\n{\"command\": \"cd foo && cargo build\"}\n```\n\nIf a command is still running at that boundary, the same process continues in\nthe background. The response returns its PID and linked output resource, and a\ncompletion notification arrives when it exits. There is no `background` flag\nand the command is never killed or restarted during the handoff. Multiple\ndistinct commands may run concurrently, including from the same working\ndirectory. An exact duplicate command in the same working directory is rejected\nwhile the first copy is still running.\n\n> On Windows, shutdown cleanup terminates only direct child processes (no Unix\n> process-group semantics); use `taskkill /PID <pid> /T` for process trees.\n\n---\n\n### `workdir` — Manage working directory\n\n**Get current:**\n```json\n{}\n```\n\n**Set new:**\n```json\n{\"path\": \"/path/to/project\"}\n```\n\n**Reset to session root:**\n```json\n{\"reset\": true}\n```\n\n---\n\n## Architecture\n\n```\noctofs/\n├── src/\n│   ├── main.rs                  # Entry point, STDIO/HTTP server setup, signal handling\n│   ├── cli.rs                   # CLI argument parsing (clap): octofs mcp [OPTIONS]\n│   ├── mcp/\n│   │   ├── mod.rs               # McpToolCall, SessionRoot\n│   │   ├── server.rs            # OctofsServer (rmcp tool impl), Params structs, SessionWorkdir\n│   │   ├── request_ctx.rs       # Per-request hint queue + stale-file stamps\n│   │   └── fs/                  # Filesystem tool implementations\n│   │       ├── mod.rs           # Re-exports\n│   │       ├── core.rs          # view, text_editor, batch_edit, extract_lines\n│   │       ├── file_ops.rs      # view_file_spec, create_file_spec\n│   │       ├── text_editing.rs  # str_replace, batch_edit, undo, per-file locking\n│   │       ├── directory.rs     # Directory listing + content search\n│   │       ├── search.rs        # search_content\n│   │       ├── shell.rs         # Command execution, background, process cleanup\n│   │       ├── workdir.rs       # Working directory management\n│   │       ├── remote.rs        # SSH/SFTP path abstraction, SshHandler, SFTP pool\n│   │       └── fs_tests.rs      # Integration tests (cfg(test))\n│   └── utils/\n│       ├── mod.rs               # Module re-exports\n│       ├── line_hash.rs         # Composite line ids (N:hh), FNV-1a hashes, endpoint parsing\n│       └── truncation.rs        # Token estimation, smart truncation\n```\n\n**Key design decisions:**\n\n- **rmcp SDK** — Official Rust MCP SDK (`rmcp` 3.x) for protocol handling\n- **Tokio** — Async runtime; all file I/O uses `tokio::fs`, never blocking `std::fs`\n- **File locking** — Per-file `tokio::sync::Mutex` prevents concurrent write conflicts\n- **Undo history** — Up to 10 snapshots per file, in-memory (lost on restart)\n- **Path resolution** — Relative paths resolve against the session workdir; no canonicalization (files may not exist yet)\n- **Stale-write detection** — every edit target's `N:hh` id is verified against the file at apply time; a stale id fails with the current content instead of editing the wrong line\n\n---\n\n## Development\n\n```bash\n# Build\ncargo build --release\n\n# Run tests\ncargo test\n\n# Lint (zero warnings policy)\ncargo clippy\n\n# Format\ncargo fmt\n\n# Run locally\ncargo run -- mcp\n```\n\n### Running Tests\n\n```bash\n# All tests\ncargo test\n\n# Specific test\ncargo test test_view_file\n\n# With output\ncargo test -- --nocapture\n```\n\n---\n\n## Contributing\n\nWe welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.\n\n**Quick checklist:**\n1. Run `cargo fmt` before committing\n2. Ensure `cargo clippy` passes with zero warnings\n3. Add tests for new functionality\n4. Update documentation as needed\n\n---\n\n## Security\n\nSee [SECURITY.md](SECURITY.md) for security policy and reporting vulnerabilities.\n\n---\n\n## License\n\nApache-2.0 — See [LICENSE](LICENSE)\n\n---\n\n## Acknowledgments\n\n- [rmcp](https://crates.io/crates/rmcp) — Official Rust MCP SDK\n- [Model Context Protocol](https://modelcontextprotocol.io) — The protocol specification\n\n---\n\n<div align=\"center\">\n\n**Built with 🦀 by [Muvon](https://muvon.io)**\n\n*Star us on GitHub if Octofs helps you ship faster! ⭐*\n\n</div>\n",
  "bytes": 23170,
  "sha": "57f4f47cfd27248c68364bf9e57b7908bb5c497c63fc57af9f54b20fb0679643",
  "repo_slug": "muvon/octofs",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_muvon_octofs_7ab6b900/readme"
}