Skip to content

feat: add MCP server for artifact cleanup - #17

Closed
NotYash1066 wants to merge 1 commit into
kunjee17:mainfrom
NotYash1066:feat/mcp-server
Closed

NotYash1066 wants to merge 1 commit into
kunjee17:mainfrom
NotYash1066:feat/mcp-server

Conversation

@NotYash1066

@NotYash1066 NotYash1066 commented May 11, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • add an irona --mcp stdio Model Context Protocol server
  • expose scan_artifacts and clean_artifacts tools backed by the existing scanner/deleter logic
  • document MCP client configuration and recommend adding Cargo's bin directory to PATH so configs can use command = "irona" instead of a local absolute binary path

Closes #16

Verification

  • cargo test passed: 54 tests
  • pre-commit hook passed: fmt, clippy, build
  • installed binary smoke-tested with MCP initialize and tools/list
  • tested the MCP connection in Codex; Codex discovers the irona tools and scan_artifacts / clean_artifacts work end to end

Notes

This intentionally keeps cleanup destructive only through explicit clean_artifacts path arguments; scan_artifacts is read-only.

Expose irona over stdio MCP while reusing the existing scanner and deleter paths. Document PATH-based configuration so MCP clients can call irona portably instead of hardcoding a user-local binary.

Constraint: MCP clients launch servers by command and args, so the binary must support a non-TUI stdio mode.

Rejected: Separate irona-mcp crate | unnecessary split for two tools that reuse existing core behavior.

Confidence: high

Scope-risk: moderate

Directive: Keep MCP cleanup destructive only through explicit clean_artifacts path arguments; do not make scan_artifacts delete anything.

Tested: cargo test; pre-commit fmt and clippy hook; installed binary smoke-tested with initialize and tools/list; Codex MCP command verified after local config wiring.

Not-tested: End-to-end startup from a freshly restarted Codex process.

@kunjee17 kunjee17 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this — the MCP layer is well built. The JSON-RPC framing is correct, notifications properly get no response (message.get("id")? returning None is the right shape), the tool definitions carry real outputSchema and annotations rather than the bare minimum, and you kept it to a single new dependency with hand-rolled JSON, which fits how the rest of this codebase is written. 54 tests passing and clippy clean on my machine too.

Two things came up in review that I wanted to explain rather than just point at.

clean_artifacts will delete any path it is given

Caller-supplied strings go straight to remove_dir_all with nothing in between:

let path = PathBuf::from(path);
sizes.push(scanner::dir_size(&path));
original_paths.push(path.clone());
delete_inputs.push((index, path));   // no validation

I tested it against the built binary rather than assuming. A plain directory with a text file in it and no marker file:

$ echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"clean_artifacts",
  "arguments":{"paths":["/tmp/irona-notartifact/my-documents"]}}}' | irona --mcp
{"result":{"structuredContent":{"deleted_count":1,"total_freed_bytes":10, ...

Gone.

I read your note that cleanup is "destructive only through explicit clean_artifacts path arguments", and in a normal CLI that reasoning would hold — the caller typed the path. What makes this different is that the caller is a model. The argument is generated, not typed, so it can be wrong from a hallucination or from something the model read earlier in the session. destructiveHint: true helps, but it is advisory and clients are not obliged to confirm on it, so there is no backstop when they don't.

The fix is small: canonicalize each path and check it against the scanner's own detection before deleting.

The scanner refactor cost the TUI its streaming

Turning par_iter().for_each(|..| tx.send(..)) into par_iter().map(..).collect() means nothing is sent until the whole parallel phase finishes. dir_size is the slow part — it walks every file under each candidate — and the TUI used to fill in progressively while that ran. Now the list stays empty until the entire scan completes, which is very visible on a large workspace.

Both callers can be served by pulling phase 1 into a shared helper: scan keeps streaming, scan_artifacts collects.

Where this landed

I could not push to your fork branch from my environment, so rather than leave this waiting I opened #19, which carries your commit forward unchanged with one fix commit on top addressing both points, plus tests. Your authorship is preserved in the history. I'm closing this one in favour of that.

Genuinely nice work — the issues above are about the trust boundary an MCP tool sits on, not about the implementation. Two smaller things I left alone and noted on #19 as follow-ups: initialize echoes back whatever protocolVersion the client sends including unsupported ones, and scan_artifacts has no cap on result count, so scanning a large tree could return a lot of entries into a model's context.

kunjee17 added a commit that referenced this pull request Jul 26, 2026
…ard) (#19)

* Enable AI clients to manage artifacts through MCP

Expose irona over stdio MCP while reusing the existing scanner and deleter paths. Document PATH-based configuration so MCP clients can call irona portably instead of hardcoding a user-local binary.

Constraint: MCP clients launch servers by command and args, so the binary must support a non-TUI stdio mode.

Rejected: Separate irona-mcp crate | unnecessary split for two tools that reuse existing core behavior.

Confidence: high

Scope-risk: moderate

Directive: Keep MCP cleanup destructive only through explicit clean_artifacts path arguments; do not make scan_artifacts delete anything.

Tested: cargo test; pre-commit fmt and clippy hook; installed binary smoke-tested with initialize and tools/list; Codex MCP command verified after local config wiring.

Not-tested: End-to-end startup from a freshly restarted Codex process.

* fix: gate clean_artifacts on artifact detection, restore scan streaming

clean_artifacts passed caller-supplied paths straight to remove_dir_all
with no validation. Since the caller is a model, a hallucinated or
injected path meant silent recursive deletion of arbitrary directories —
verified against the built binary on a plain directory holding a text
file. Every path is now canonicalized and checked with scanner::is_artifact,
which accepts a directory only when a marker file sits beside it or a
.gitignore rule matches it. One bad path fails the whole call.

Splitting scan into scan_artifacts also cost the TUI its streaming: the
parallel dir_size phase collected into a Vec before sending anything, so
the list stayed empty until the whole scan finished. Phase 1 is now a
shared collect_candidates helper, letting scan keep sending each entry as
its size lands while scan_artifacts collects for MCP.

Also reports isError when some deletions fail rather than always false.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Karthiya Yash Kiranbhai <160919026+NotYash1066@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
@kunjee17 kunjee17 closed this in #19 Jul 26, 2026
@kunjee17

Copy link
Copy Markdown
Owner

Landed via #19 — your commit carried forward with a delete guard on clean_artifacts and the TUI's streaming scan restored. The MCP layer itself shipped essentially as you wrote it. Thanks for building this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: MCP server for AI-native artifact management

2 participants