Metadata-Version: 2.5
Name: af-filesystem-mcp
Version: 0.2.0
Summary: MCP server for per-user, impersonated filesystem access on the AF platform
Project-URL: Homepage, https://github.com/maniaclab/af-filesystem-mcp
Project-URL: Bug Tracker, https://github.com/maniaclab/af-filesystem-mcp/issues
Author-email: Giordon Stark <kratsg@gmail.com>
License-Expression: Apache-2.0
License-File: LICENSE
Classifier: Development Status :: 1 - Planning
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: mcp<3,>=2.0.0
Provides-Extra: broker
Requires-Dist: af-credentials[mcp]>=0.2.0; extra == 'broker'
Description-Content-Type: text/markdown

# af-filesystem-mcp v0.2.0

<!-- --8<-- [start:intro] -->

An MCP server that gives an AF (Analysis Facility) user browse/read access to
their own files on the AF's shared NFS home (`/home/<unixname>`) and Ceph data
area (`/data/<unixname>`) — nothing more. Designed to sit behind
af-mcp-platform's credential broker so an LLM session can look at a user's own
analysis outputs, condor logs, and scratch files without a human copying paths
around.

<!-- --8<-- [end:intro] -->

<!-- --8<-- [start:what-it-does] -->

## What it does

| Tool      | Does                                                                                              | Read/write |
| --------- | ------------------------------------------------------------------------------------------------- | ---------- |
| `fs_list` | List a directory                                                                                  | read-only  |
| `fs_read` | Read a file, by byte range or line range, including head/tail                                     | read-only  |
| `fs_stat` | Stat a path — size, mtime, type, permissions                                                      | read-only  |
| `fs_grep` | Search for a pattern across files under a directory, capped in files scanned and matches returned | read-only  |

That is the entire v1 tool surface: all four tools are read-only
(`read_only_hint=true` in their MCP tool annotations) and confined to the
caller's own two AF roots (`open_world_hint=false`). There is deliberately no
write tool, no delete, no chmod, no arbitrary command execution, and no
full-tree walk (directory-size, duplicate-finder). See `CLAUDE.md` for the
design rationale and phase-2 (write) plan.

<!-- --8<-- [end:what-it-does] -->

<!-- --8<-- [start:security-model] -->

## Security model

Every filesystem operation for user _alice_ runs in a short-lived helper
subprocess **impersonating alice's real uid/gid** — the server process itself
(running as root, holding only `CAP_SETUID`/`CAP_SETGID`) never reads or writes
a byte of user data directly. This means the kernel (and, for the NFS-mounted
homes, the NFS server) enforces every permission check against the real
identity: even a bug in this server's own path-pinning logic can only let alice
reach what alice's real uid could already reach. See `CLAUDE.md` § "Security
model" and `src/af_filesystem_mcp/paths.py` for the full design rationale, and
[maniaclab/af-mcp-platform#188](https://github.com/maniaclab/af-mcp-platform/issues/188)
for the workplan and the (rejected) alternatives this design was chosen over.

<!-- --8<-- [end:security-model] -->

<!-- --8<-- [start:installation] -->

## Installation

```bash
pip install af-filesystem-mcp
```

Or with pixi:

```bash
pixi add af-filesystem-mcp
```

<!-- --8<-- [end:installation] -->

## Requirements

- Python 3.10+
- Linux (the impersonation mechanism is POSIX `setuid`/`setgid`; there is no
  Windows/macOS deployment target — local `stdio` mode runs fine on any OS for
  development, since it never impersonates)

<!-- --8<-- [start:usage] -->

## Quick start (local development, stdio)

In `stdio` mode there is exactly one caller (you), so no impersonation happens —
the server operates directly as your own uid/gid, confined to your own `$HOME`
and a configurable data root:

```bash
af-filesystem-mcp serve --data-root /data
```

## Broker mode (production, HTTP)

```bash
af-filesystem-mcp serve --transport http \
  --broker-url https://mcp.af.uchicago.edu \
  --broker-audience af-filesystem-mcp \
  --home-root /home --data-root /data
```

Bearers are broker-issued identity JWTs (`aud=af-filesystem-mcp`) carrying
`uid`/`gid`/`unixname` POSIX claims (af-mcp-platform's
`identityProviders[].targetOptions.af-filesystem-mcp.includePosix: true`).
Requires the `broker` extra: `pip install af-filesystem-mcp[broker]`.

<!-- --8<-- [end:usage] -->

## Development

```bash
pixi install
pixi run test
pixi run lint
```

See `CLAUDE.md` for architecture, the impersonation/path-confinement design, and
conventions for adding a new tool.
