Skip to main content
Glama

Legwork

PyPI CI License: MIT

Your AI finds the open-source tool it needs on GitHub. Legwork installs it in a sandbox.

https://github.com/user-attachments/assets/9e9b80b5-99ff-4d21-b689-74655418f23d

Add Legwork to Claude, Cursor, Codex, opencode or any MCP client once. When you ask for something your AI has no tool for, it searches GitHub, picks a repo, and asks you to approve installing it. Legwork then checks the code for hidden payloads, builds a working tool for it in a sandbox, tests it, and hands it over. In your home folder it can only read the folders you allow.

claude mcp add legwork -- uvx legwork-mcp hub --allow-read ~/Downloads

Then just ask. Four to try first, all from the public cache, so they need no API key:

  • "Use Legwork to transcribe ~/Downloads/memo.m4a." Any voice memo, mp3 or video, offline. Best in English and other widely spoken languages; its small built-in model is unreliable for languages like Telugu.

  • "Use Legwork to remove the background from ~/Downloads/photo.jpg."

  • "Use Legwork to pull the tables out of ~/Downloads/report.pdf."

  • "Use Legwork to make a QR code for https://github.com/kumarganduri/legwork."

Saying "use Legwork" matters in Claude Desktop: without it, Claude may reach for its own cloud code sandbox, which can't see the files on your computer unless you attach them.

Your AI finds the tool (faster-whisper, rembg, pdfplumber, qrcode), you approve the install, and about a minute later it does the job. Files a tool makes are copied to ~/Legwork/outputs/. On macOS, the first time a tool reads Downloads, macOS asks whether uvx may access it; allow it once. If something doesn't work, uvx legwork-mcp doctor checks your setup. Or build one tool yourself: uvx legwork-mcp owner/repo (a model key for repos not in the cache).

Why not just ask your AI to install it?

  • Most repos have no MCP server to install. Your AI would have to write one on the spot, untested, every time. Legwork writes it once, proves it works with a self-test, and caches it so the next person doesn't pay for it.

  • Whatever your AI installs runs with full access to your machine: your SSH keys, your files, your environment variables. That's how the two malware repos below would have got in. Legwork checks the code for obfuscated payloads first, and every tool it installs runs sandboxed: in your home folder it sees only the folders you grant.

  • It works across your tools: the same install works in Claude Code, Claude Desktop, Cursor, opencode, Codex CLI, Goose and OpenClaw.

Related MCP server: Gitingest-MCP

What it did on real repos

On 2026-09-26 we ran Legwork against the 10 most-starred AI repos created on GitHub in the previous week, taken exactly as search ranked them, with nothing skipped for being hard:

Outcome

Repos

✅ Built a working MCP server

3 — an npm CLI, a Python library, a Go binary

↩️ Refused, with the right reason

5 — two Android/macOS apps, a desktop app, a repo with no usage docs, a tool that needs its own API keys

🛑 Blocked before install (malware)

2

Two of those top-10 "AI tools", about 700 stars each and three days old at the time, carried the same byte-identical obfuscated dropper under different file names. Legwork's pre-install scan refused both in about a second. Nothing from them was installed or run. Stars are not a trust signal.

The tripwire has to stay quiet on ordinary code too. Run over the 150 most-starred Python, JavaScript and TypeScript repos on GitHub (2026-10-01), it blocks one: lodash, for a vendored 2009 debugging script that really does run eval(unescape(...)).

Full write-up, including what failed along the way and what we fixed: docs/designs/legwork-trending-trial-2026-09-26.md.

A second, larger run on the next 22 new trending repos, with two models: gpt-5 built 12 and refused 10 with reasons, with no crashes; OpenRouter's free Nemotron built 4. That run also caught two false malware alarms and a gap where only published packages could be installed, both fixed. Write-up.

Let your AI find its own tools (hub)

legwork hub is one MCP server that gives your AI five tools: find_tools, install_tool, install_status, list_installed_tools and use_tool.

claude mcp add legwork -- uvx legwork-mcp hub --allow-read ~/Downloads

For Claude Desktop (macOS), download legwork.mcpb and double-click it. Desktop installs it as an extension and lets you pick the folders tools may read (Downloads by default) and whether they may use the internet, under Settings → Extensions → Legwork → Configure. It runs the released legwork-mcp from PyPI, pinned to that release.

Or, for Cursor or Claude Desktop without the extension, add this to the MCP config (for Claude Desktop, while the app is quit), with your own user name in the path: a folder that doesn't exist stops the hub from starting.

{ "mcpServers": { "legwork": { "command": "uvx",
  "args": ["legwork-mcp", "hub", "--allow-read", "/Users/you/Downloads"] } } }

For opencode, add this to ~/.config/opencode/opencode.json. opencode runs MCP tools without asking by default, so the permission line is what makes it ask you before an install:

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": { "legwork": { "type": "local",
    "command": ["uvx", "legwork-mcp", "hub", "--allow-read", "~/Downloads"] } },
  "permission": { "legwork_install_tool": "ask" }
}
  • You approve every install: your client shows the repo and the folders it asks for.

  • The hub's flags are the ceiling. An install can ask for the folders you allowed or less, never more, and no network unless you started the hub with --allow-net. Secret folders (~/.ssh, ~/.aws, ...) are refused outright.

  • Installed tools appear by name (pdfplumber__extract_tables), and use_tool works in clients that don't refresh their tool list. Installs are remembered across restarts.

  • Search results tell your AI what matters: stars, license, how recently the repo was updated, whether it's in the Legwork cache, whether it already has an MCP server, and a warning on very new repos (the malware we caught was three days old). Descriptions are marked as untrusted text.

37 tools are in the public cache and install in about a minute with no API key: speech-to-text, OCR, background removal, PDFs and Office files, video, YouTube transcripts, charts, DuckDB and CSV tools, maths and units, and linters and formatters. Each was built, reviewed by hand and tried with a real call before it was added, and pins the version of the package it wraps (its dependencies resolve at install). The cache a release reads is the one tagged with that release, so a change to the cache reaches you only with an upgrade. Others need a model key, and building takes 1–5 minutes. Put the key in ~/.legwork.env (three lines, chmod 600) and the hub reads it when it needs to build, so the key never goes in your MCP config, where it would sit in plain text.

legwork find "extract tables pdf" runs the same search from your terminal.

  • Tools that use the internet (YouTube transcripts and downloads, web pages) need the hub started with --allow-net; without it they install, then can't connect.

  • Files a tool makes (a trimmed video, a chart, a QR code) are copied to ~/Legwork/outputs/<tool>/, and the reply says where; images also come back inline. Your granted folders stay read-only, so a tool can't write next to your files. The copies are never executable, and on macOS they get the same quarantine flag as downloads. --outputs DIR puts them elsewhere, --outputs off turns copying off.

  • GitHub allows 10 searches a minute without a token, and each find_tools uses 2 to 4. Cached tools still show up when GitHub says no. For 30 a minute, add GITHUB_TOKEN=<a GitHub token with no scopes> to ~/.legwork.env.

Other MCP clients

Legwork is a standard MCP server over stdio, so any client that runs local MCP servers can use it. What differs is whether the client asks you before it calls a tool. Legwork labels its tools (searching only reads; installing acts), and the clients marked "asks" use those labels.

Client

Tested

Add Legwork

Before an install

Claude Code

✅

claude mcp add legwork -- uvx legwork-mcp hub --allow-read ~/Downloads

asks

Claude Desktop

✅

JSON above

asks

Cursor

✅

JSON above

its default Auto-review mode lets an AI decide, and ran installs without asking in our test; to approve every install, set Settings → Agents → Approvals & Execution to Allowlist and leave install_tool off the list

opencode

✅ 1.18

JSON above

asks only with the permission line above

Codex CLI

✅ 0.159

codex mcp add legwork -- uvx legwork-mcp hub --allow-read ~/Downloads

asks

Goose

✅ 1.52

goose session --with-extension "uvx legwork-mcp hub --allow-read ~/Downloads"

asks with GOOSE_MODE=smart_approve; the default mode doesn't

OpenClaw

✅ 2026.9

openclaw mcp add legwork --command uvx --arg legwork-mcp --arg hub --arg --allow-read --arg ~/Downloads

its default full-permission mode doesn't ask

Gemini CLI, Cline, Zed, Continue, ...

not yet

the same command in the client's MCP config

check the client's settings

In every client, the folders and network you start the hub with stay the ceiling, whether or not the client asks.

Faster starts: uvx downloads Legwork on the first run, which can be slower than some clients wait (Codex allows 10 seconds; add startup_timeout_sec = 60 under [mcp_servers.legwork] in ~/.codex/config.toml). Or install it once with uv tool install legwork-mcp and use the full path that which legwork prints, plus hub ..., as the command (desktop apps don't see your shell's PATH); uv tool upgrade legwork-mcp updates it.

Quick start

You need macOS or Linux and uv. Tools in the public cache need nothing else. For any other repo you also need a model key for an OpenAI-compatible chat-completions endpoint (see Model providers). Legwork itself is free; the only cost is your own model usage, which is 1–3 calls per build.

The Linux sandbox is bubblewrap:

sudo apt install bubblewrap python3-venv   # Debian/Ubuntu
sudo dnf install bubblewrap                # Fedora

Ubuntu 24.04 and later block the user namespaces bubblewrap needs, unless a program's AppArmor profile allows them. Allow them for bwrap only (this is what Ubuntu does for Chrome and Flatpak), rather than switching the restriction off system-wide:

sudo tee /etc/apparmor.d/bwrap <<'EOF'
abi <abi/4.0>,
include <tunables/global>

profile bwrap /usr/bin/bwrap flags=(unconfined) {
  userns,
  include if exists <local/bwrap>
}
EOF
sudo apparmor_parser -r /etc/apparmor.d/bwrap

If anything's missing, Legwork stops and prints these instructions.

Tested on every commit: macOS on Apple silicon and Intel; Ubuntu on x86-64 and ARM64; Fedora; Debian. Windows: not supported natively. WSL2 should behave like Ubuntu (install bubblewrap) but hasn't been tested.

A repo in the public cache needs no model and no API key:

uvx legwork-mcp jsvine/pdfplumber

It installs and tests the cached wrapper in about a minute, then prints the line to connect it:

Installed the cached MCP wrapper for jsvine/pdfplumber; it passed its self-test here.
  What it wraps: Extract text, tables, and low-level page objects from local PDFs using pdfplumber's Python API

Connect it to Claude Code:
  claude mcp add pdfplumber -- ~/.local/bin/uvx legwork-mcp serve jsvine/pdfplumber

For any other repo, Legwork has a model write the wrapper (1–5 minutes, 1–3 model calls on your own key; see Model providers):

export LEGWORK_LLM_ENDPOINT=https://api.openai.com/v1
export LEGWORK_LLM_API_KEY=...        # your own key; never a CLI flag
export LEGWORK_LLM_MODEL=gpt-5

uvx legwork-mcp owner/repo

It also prints an mcpServers block for Claude Desktop, Cursor and other clients. For Claude Desktop, add it to claude_desktop_config.json while the app is quit: the running app writes its settings back on exit and drops edits it didn't make. For a permanent legwork command: uv tool install legwork-mcp.

Upgrading: uvx keeps using the version it first downloaded. To get fixes (and the cache that ships with them), use uvx legwork-mcp@latest once, or uv cache clean legwork-mcp. legwork doctor warns when a client is pinned to an old version.

The name: the package is legwork-mcp. pip install legwork and uvx legwork install an unrelated astronomy package.

Model providers

Any OpenAI-compatible chat-completions endpoint works. Put three lines in ~/.legwork.env and make it private with chmod 600 ~/.legwork.env; Legwork reads it whenever the variables aren't set in your environment (and refuses it if other users can read it):

LEGWORK_LLM_ENDPOINT=https://api.openai.com/v1
LEGWORK_LLM_API_KEY=sk-...
LEGWORK_LLM_MODEL=gpt-5

Provider

LEGWORK_LLM_ENDPOINT

LEGWORK_LLM_MODEL (tested)

Cost

OpenAI

https://api.openai.com/v1

gpt-5

Your API credits

Anthropic

https://api.anthropic.com/v1

claude-sonnet-5

Your API credits

OpenRouter

https://openrouter.ai/api/v1

nvidia/nemotron-3-super-120b-a12b:free

Free models, rate-limited

Ollama (local)

http://127.0.0.1:11434/v1

gpt-oss:20b

Free; 14 GB download, ~16 GB RAM

LEGWORK_LLM_API_KEY is your key (for Ollama, any non-empty value).

Ollama: start it with a larger context window, or it silently cuts Legwork's prompt to ~2,000 tokens and the model never sees the instructions: OLLAMA_CONTEXT_LENGTH=32768 ollama serve. Legwork prints this tip when it detects Ollama.

OpenRouter free models come and go and are often busy (HTTP 429). If one keeps failing, pick another from their list.

Measured 2026-09-27, same four repos on each (reverify, golive-skill, AnyJev, phone-harness), counting wrappers built:

Model

Built

Notes

gpt-5

4 / 4

all on the first attempt

Nemotron 3 Super (OpenRouter, free)

3 / 4

gpt-oss:20b (Ollama, local)

3 / 4

slowest: 1–3 min per reply on an M5

Claude Sonnet 5

1 / 4

the most cautious: refused three, citing third-party accounts, a paired iPhone, and "a research pipeline"

A refusal isn't a crash: Legwork reports the model's reason and stops without installing anything.

How it works

  1. Cache. If the repo is in the public cache, Legwork uses that wrapper instead of steps 3–4. It still clones and scans the repo, scans the cached wrapper too, and installs and self-tests it locally; if the self-test fails, it writes a fresh wrapper. --no-cache skips the cache.

  2. Fetch. Checks the repo is public and reachable, then shallow-clones it.

  3. Scan. Statically scans every Python and JavaScript/TypeScript file for obfuscated payloads: XOR-decoded byte arrays, computed imports, javascript-obfuscator output, eval of decoded strings, code hidden off-screen behind whitespace. A hit stops everything before install.

  4. Read. The README, plus setup docs it links to (install.md, docs/getting-started.md, …), capped at 50KB with install and usage sections kept first.

  5. Write. Your model writes the install command and a Python MCP wrapper with a self-test, or refuses with a specific reason: no programmatic entrypoint, needs hardware, needs its own credentials, needs a toolchain the sandbox doesn't have, and so on.

  6. Install, sandboxed, network on.

  7. Self-test, sandboxed, network off. A failure goes back to the model and it tries again, up to 3 attempts and 30 minutes. Attempts share one download cache, so a retry doesn't re-download multi-GB dependencies like PyTorch.

  8. Serve. legwork serve owner/repo runs the wrapper as an MCP server over stdio, sandboxed, network off.

Permissions: locked down unless you say so

A served tool can't read your home folder and has no network until you grant them. Grant exactly what a tool needs when you add it to your client:

# Build it once (cached: no key needed), then let it read one folder (read-only):
uvx legwork-mcp microsoft/markitdown
claude mcp add markitdown -- uvx legwork-mcp serve microsoft/markitdown --allow-read ~/Downloads

# A tool that fetches web pages:
uvx legwork-mcp serve owner/repo --allow-net

--allow-read is repeatable and always read-only. Some folders can't be granted even on request: /, your whole home folder, and a list of known credential locations (~/.ssh, ~/.aws, ~/.config, ~/.gnupg, macOS keychains and browser data, Linux keyrings and Firefox profiles, ~/.npmrc, ~/.pgpass, ~/.legwork.env, shell history and startup files, AI clients' configs), and any folder that contains one of those (such as ~/Library). It's a list, so it can miss a place your setup keeps secrets.

A granted folder is readable in full, including any .env file or key inside it: grant ~/Downloads, not your code folder. A tool with a folder and --allow-net could send what it reads to the internet, so grant both only to a tool that needs both. With --allow-net, the tool can reach services on this machine (localhost) but not local sockets such as your SSH agent or Docker.

Outside your home folder, tools can read system locations such as /usr, /opt, /etc, /tmp, macOS's per-user temporary folder, /Users/Shared and external drives under /Volumes, because Python and the libraries they need live there. Don't keep secrets in those places. (On Linux, /tmp is a private empty one.)

On macOS, the first time a tool reads a protected folder (Downloads, Documents, Desktop), macOS itself asks whether uvx may access it. That's the operating system's own privacy check, on top of Legwork's grant; allow it once.

What "built" means

The self-test calls the simplest documented command and checks the shape of its result. So "built" means the wrapper starts and its simplest tool works. It does not mean every tool works. In the trial:

  • golive-skill's wrapper exposes its read-only commands, not its deploy flow, which needs accounts.

  • AnyJev's decision tool needs a running vLLM server, which the self-test didn't have.

The same model writes the wrapper and its self-test, so a wrapper that misread the README can pass its own wrong test. Cached tools have one more check: a known answer, a fixed input and the output a person expects from it, which must pass before an entry is added or changed (#3).

Tools that must reach the network at run time need --allow-net; without it the network is off.

Risks, stated plainly

Legwork runs code you didn't write: the target repo's install steps and a wrapper an LLM wrote from a README a stranger wrote. What contains it:

  • Install time is the biggest risk. Package installs and install.sh scripts run with network on, because they have to. The sandbox limits them to their own working folder: no access to your home directory (SSH keys, cloud credentials, dotfiles; system locations such as /tmp stay readable), no writes outside the folder, and an environment with none of your variables (including your model key). A malicious package can still misbehave inside that folder and reach the network during install. Legwork records which hosts it reached (legwork log owner/repo); see THREAT_MODEL.md for what that record can miss.

  • The scan covers the repo's source, not what installers download. magpie, for example, installs with the vendor's curl … | sh. For downloaded code, the sandbox is the protection.

  • Prompt injection is not mitigated. A README can steer the model into writing a wrapper that does something other than what you asked for. The wrapper still runs sandboxed with network off, which bounds the damage; it doesn't prevent a wrong or misleading tool.

  • Linux on architectures other than x86-64 and ARM64: install code can reach "abstract" Unix sockets (such as an X11 display), because the seccomp filter that blocks Unix sockets during install only covers those two. The run phase has no network and isn't affected.

  • macOS can't stop a process that detaches itself. Each install and self-test is cleaned up when it finishes, but on macOS code that deliberately detaches (setsid) can keep running afterwards. It stays in the sandbox (no home folder, no writes outside its own folder) but keeps the install step's network access until you log out. Linux's sandbox stops these too.

  • Keep your key file in your home folder (~/.legwork.env, the default). Sandboxed code can't read your home folder, but it can read most places outside it.

  • Installs on Linux can reach services on this machine (localhost databases, dev servers): bubblewrap shares the host's network during install. macOS blocks them. Unix sockets are blocked on both.

  • Not yet: legwork serve used on its own passes along anything a tool prints by mistake, which can confuse a client (the hub filters it out).

  • The scan is an obfuscation tripwire, not a malware scanner. It catches the hiding patterns seen in real payloads so far, and a determined author can get past it. The sandbox is the protection.

The sandbox is sandbox-exec on macOS and bubblewrap on Linux, with the same rules on both: the system read-only, your home directory hidden, writes only in the build's own folder, no local sockets (SSH agent, Docker, display servers), only the system services builds need, and network only during install. If the sandbox isn't available, Legwork refuses to run. It never falls back to running unsandboxed.

THREAT_MODEL.md has the full table of what a tool can reach in each phase, a comparison with Docker and VMs, and every escape found so far with the test that keeps it fixed.

Commands

Command

What it does

legwork hub [--allow-read PATH] [--allow-net]

One MCP server through which your AI finds, installs and uses tools, within the limits you set

legwork find "keywords"

Search GitHub for tools that do something, with facts to choose by

legwork owner/repo

Build a wrapper (also legwork build), from the cache when possible. Accepts owner/repo or a github.com URL. --no-cache always writes a fresh one

legwork serve owner/repo

Run the built wrapper as an MCP server over stdio. Needs no model key. --allow-read PATH, --allow-net grant access (see Permissions)

legwork contribute owner/repo [--out DIR]

Write the build as a public-cache entry, ready for a PR (below)

legwork doctor

Check this machine is ready: sandbox, cache, key, search limit, client configs. Read-only; prints no keys. Paste it into bug reports

legwork show owner/repo

What a built tool came from: the commit that was scanned, the wrapper's hash, the install command and every package it installed

legwork log owner/repo

A tool's record, written by Legwork outside the sandbox: the hosts each install reached, and what the sandbox blocked while it ran (macOS)

legwork clean [owner/repo]

Free disk space: remove old and failed builds, keep the ones you serve. --dry-run, --all

Builds live in ~/.legwork (override with LEGWORK_HOME). A failed build saves its full error output to attempts.log in its build folder. Each build keeps its own environment, which is several GB for repos that use PyTorch: legwork clean removes old and failed builds and keeps the ones you serve (--dry-run to preview, --all to remove everything).

Contributing a wrapper

legwork contribute owner/repo writes cache/<owner>__<repo>/ containing wrapper.py and manifest.json, and prints a PR description. Before writing anything, it:

  • blocks the entry if the wrapper copies 50+ words in a row from the source repo

  • re-runs the self-test in the sandbox

  • blocks the write if any output contains something shaped like an API key, including your own configured key

A GPL, AGPL, missing or unrecognized source license is flagged in the manifest and the PR description, but not blocked. If the repo has commits newer than the build or the existing entry, you get a warning. Open the PR yourself; a bad entry is removed with a plain git revert.

Status

Early. What's next:

  • Better multi-tool verification than a single simplest-command self-test.

Development

See CONTRIBUTING.md. Security reports: SECURITY.md.

uv sync
uv run pytest        # sandbox tests need macOS, or Linux with bubblewrap

tests/fixtures/ai_data_extractor_payload.py is a real malicious file with its payload destroyed (every encoded byte randomized, code shape kept), so the scanner is tested against a real technique. Tests only parse it with ast; see tests/fixtures/README.md.

License

MIT

Available Tools

5 tools
find_toolsA
Read-only

Find a tool that runs on the user's own computer for a job you have no tool for, especially work on their local files (paths like ~/Downloads/memo.m4a, /Users/..., /home/...): transcribe audio, pull tables from a PDF, remove an image background, convert documents, trim video. A cloud code sandbox can't see the user's files unless they attached them; a tool installed through Legwork runs on their machine and reads the folders they allowed. Searches GitHub and the Legwork cache, with facts to choose by (stars, license, freshness, cached, already has an MCP server). Installs nothing.

ParametersJSON Schema
NameRequiredDescriptionDefault
queryYes2-3 keywords, e.g. 'extract tables pdf'. Every word must match on GitHub, so leave out filler; if the results look off, try fewer or different words.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=true, so safety is covered; the description still adds real context beyond that: it searches GitHub AND the Legwork cache, returns selection facts (stars, license, freshness, cached, already has an MCP server), and explicitly states no installation occurs. Only the pagination/result-count behavior is left unspecified.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose and the local-file trigger are front-loaded, and the sandbox-vs-local-machine contrast justifies the tool's existence rather than padding. It runs slightly long, with the second sentence restating the local-file rationale already implied by the path examples.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, yet the description compensates by naming the facts returned (stars, license, freshness, cached, MCP-server availability) and the two search sources. Combined with the when-to-use guidance and the no-install guarantee, an agent has everything needed to call this correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the single query parameter already documents the 2-3 keyword format and filler-word caveat. The description adds only the provenance context (GitHub vs Legwork cache) that explains why keywords must match literally, so baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (find) and resource (a tool that runs on the user's own computer) and immediately scopes it to jobs the agent has no tool for, with concrete example tasks (transcribe audio, pull tables from a PDF). This is clearly distinguishable from install_tool/use_tool/list_installed_tools in the sibling set.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly frames when to reach for it (no existing tool for the job, especially local-file work with example paths like ~/Downloads/memo.m4a), and implicitly excludes the cloud sandbox route by explaining it cannot see unattached user files. 'Installs nothing' also routes the agent to install_tool for the follow-up step.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

install_statusA
Read-only

Check on an install that install_tool started, when it replied that the build is still running. Waits up to 45 seconds for it to finish, then replies with one of: still installing, with the latest build steps (call it again); installed, with the folders and network it was granted and its tools; or failed, with the reason. For a repo that was never installed, it says to call install_tool. Changes nothing.

ParametersJSON Schema
NameRequiredDescriptionDefault
repoYesowner/repo given to install_tool, e.g. 'jsvine/pdfplumber'

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Adds substantial behavior beyond the readOnlyHint/openWorldHint annotations: a 45-second blocking wait, three enumerated outcomes with their payloads, and an idempotency guarantee ('changes nothing') that is consistent with readOnlyHint=true. This is exactly the kind of timing and response-shape context annotations cannot convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads what the tool does and when to call it, then packs the outcome enumeration into one tight sentence, closing with the side-effect disclaimer. Dense but every clause carries information an agent needs.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description fully compensates by enumerating the three possible return states and what each contains, plus the timeout and retry semantics. Nothing needed to invoke or interpret the call is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and there is a single parameter, so the schema already documents 'repo' including its owner/repo format. The description only restates that it is the repo 'given to install_tool', adding no new syntax or constraint information.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a precise verb+resource ('Check on an install') and explicitly ties it to the install_tool workflow, so an agent can distinguish it from install_tool, list_installed_tools, and use_tool without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives the exact triggering condition (install_tool replied the build is still running), the retry condition (call it again if still installing), and the exclusion (for a never-installed repo, call install_tool). When-to-use and when-to-use-something-else are both explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

install_toolA
Idempotent

Install a GitHub repo, usually one picked with find_tools, as a tool on the user's computer: Legwork scans its source for hidden payloads, then builds and self-tests it in a sandbox. Grants are read-only folders and/or network, within the limits the user started Legwork with; ask only for what the task needs. Waits up to 45 seconds; if the build is still running it says so, and install_status follows it. A repo already installed with the same grants is reused, not rebuilt. Replies with the new tools' names and how to call them.

ParametersJSON Schema
NameRequiredDescriptionDefault
repoYesowner/repo (or its GitHub URL), e.g. 'jsvine/pdfplumber'
commitNooptional: a full 40-character commit SHA or a tag (e.g. v1.2.0) to build exactly that, instead of the default branch as it is now
previewNotrue: install nothing; say which commit would be built and how it would be installed, so the user can approve that exact commit
allow_netNowhether the tool may use the internet while it runs (installs always can). Omitted: keeps an earlier grant, or no
allow_readNofolders the tool may read, read-only, e.g. ['~/Downloads']. Omitted: keeps what an earlier install of this repo was granted, or none

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations cover safety hints, but the description adds substantial behavioral context beyond them: source scanning for hidden payloads, sandbox build and self-test, grants constrained to the user's Legwork limits, a 45-second wait with install_status as the fallback, and idempotent reuse of an already-installed repo. This is exactly the extra detail annotations cannot carry.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but front-loaded, leading with what it does before covering grants, wait behavior, reuse, and the reply shape. Every sentence carries information; slightly long, but nothing is filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, so the description compensates by stating that replies contain the new tools' names and how to call them, and by explaining the timeout/install_status handoff. Combined with the 100%-covered input schema, an agent has everything needed to invoke and follow up correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds real meaning: it clarifies that grants are read-only folders/network within pre-established user limits, that omitted grants persist from an earlier install, and that preview installs nothing and reports the exact commit. These reinforce and contextualize the schema fields.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (install) and resource (a GitHub repo as a tool), plus the source of the repo (usually picked with find_tools). An agent can immediately distinguish it from use_tool, find_tools, and install_status.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Routes the agent to find_tools as the usual preceding step and explains the preview path for user approval. It gives strong context on grants ('ask only for what the task needs') but does not state explicit when-not conditions or spell out all sibling alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_installed_toolsA
Read-only

List the repos already installed through Legwork on this computer. For each: the folders and network it may use, the commit it was built from, its tools and how to call them, and a link if the repo has changed upstream since. Call it before find_tools to reuse what's already installed, or to look up a tool's repo and name for use_tool. Changes nothing.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, so 'Changes nothing' reinforces rather than reveals. The value-add is describing the return payload (folders/network permissions, build commit, tools and invocation info, upstream-changed link), which matters because there is no output schema. It stops short of noting latency or staleness of the listing.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with purpose, then return contents, then routing guidance. No filler and each sentence carries distinct information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema and no parameters, the description must and does cover both the return shape and the call-time decision. An agent has everything needed to invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Zero parameters, so there is nothing to disambiguate; baseline 4 applies. The description correctly implies a parameterless listing with no filtering options.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('List the repos already installed through Legwork on this computer') and immediately scopes it against siblings by naming find_tools and use_tool. The enumeration of what each entry contains makes the deliverable unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says when to call it: before find_tools to reuse installed repos, and to look up a repo/tool name for use_tool. This routes the agent among the siblings listed in the context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

use_toolA

Call a tool of a repo installed through Legwork, by repo and tool name. Most clients also list installed tools directly as __; use this when the tool isn't in your list yet. It runs in the sandbox with the folders and network granted at install. Replies with the tool's output, marked as untrusted text and size-capped, plus (on macOS) anything the sandbox blocked; files it makes are copied to ~/Legwork/outputs/ by default. Calling a repo that isn't installed is an error that says to call install_tool; a wrong tool name is an error listing the repo's tools.

ParametersJSON Schema
NameRequiredDescriptionDefault
repoYesowner/repo of an installed tool, e.g. 'jsvine/pdfplumber'
toolYesthe tool's name as listed by install_tool or list_installed_tools, e.g. 'extract_tables'
argumentsNothe arguments for that tool, an object of its parameters, e.g. {'path': '~/Downloads/report.pdf'}. Paths may start with ~/. Omitted: no arguments

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations (readOnlyHint=false, openWorldHint=false, destructiveHint=false) by disclosing the execution sandbox and its granted folders/network, that output is marked untrusted and size-capped, that macOS reports sandbox blocks, and that produced files land in ~/Legwork/outputs/ by default. Both failure modes are described with their recovery paths.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose is front-loaded and every clause carries information (usage routing, sandbox, output handling, error behavior) with no filler. The semicolon-chained sentences are dense and slightly hard to scan, which keeps it short of a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 3-parameter dispatch tool with no output schema, the description covers invocation addressing, execution environment, return-value handling (untrusted marking, size cap, output file location), and both error cases. Nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so repo, tool, and arguments are already documented, including the owner/repo format and examples. The description reinforces the repo+tool addressing model but adds no syntax or constraints beyond what the schema states, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Call a tool of a repo installed through Legwork, by repo and tool name') and immediately distinguishes itself from the sibling tools by explaining that most clients list installed tools directly as <repo>__<tool>. An agent can tell this apart from install_tool or list_installed_tools without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly names the alternative surface ('most clients also list installed tools directly as <repo>__<tool>') and the selecting condition ('use this when the tool isn't in your list yet'). It also gives error-routing guidance: an uninstalled repo errors telling you to call install_tool, and a bad tool name errors with a list of the repo's tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 3 tool updatesv0.1.1
    • Changedinstall_status1 field changed
      • addedInput schema / properties / repo / description
        Added value: +"owner/repo given to install_tool, e.g. 'jsvine/pdfplumber'"
    • Changedinstall_tool3 fields changed
      • changedInput schema / properties / allow_net / description
        Previous value: -"whether the tool may use the network"New value: +"whether the tool may use the internet while it runs (installs always can). Omitted: keeps an earlier grant, or no"
      • changedInput schema / properties / allow_read / description
        Previous value: -"folders the tool may read"New value: +"folders the tool may read, read-only, e.g. ['~/Downloads']. Omitted: keeps what an earlier install of this repo was granted, or none"
      • changedInput schema / properties / repo / description
        Previous value: -"owner/repo from find_tools"New value: +"owner/repo (or its GitHub URL), e.g. 'jsvine/pdfplumber'"
    • Changeduse_tool3 fields changed
      • addedInput schema / properties / arguments / description
        Added value: +"the arguments for that tool, an object of its parameters, e.g. {'path': '~/Downloads/report.pdf'}. Paths may start with ~/. Omitted: no arguments"
      • addedInput schema / properties / repo / description
        Added value: +"owner/repo of an installed tool, e.g. 'jsvine/pdfplumber'"
      • addedInput schema / properties / tool / description
        Added value: +"the tool's name as listed by install_tool or list_installed_tools, e.g. 'extract_tables'"
  2. 5 tool updatesv0.1.0
    • First observedfind_tools
    • First observedinstall_status
    • First observedinstall_tool
    • First observedlist_installed_tools
    • First observeduse_tool

TDQS

A4.4/5.0

Scored across 5 tools

Disambiguation4/5

Each tool targets a distinct phase: find_tools (search), install_tool (build), install_status (check in-progress install), list_installed_tools (enumerate), use_tool (invoke). The only mild overlap is between install_status and list_installed_tools, but descriptions clearly separate in-progress builds from already-installed inventory.

Naming Consistency4/5

All names follow a verb_noun pattern (find_tools, install_tool, install_status, list_installed_tools, use_tool) and use snake_case throughout. Minor inconsistency in singular/plural (tool vs tools), but the convention is otherwise predictable.

Tool Count5/5

Five tools is well-scoped for a discover-install-run lifecycle. Each tool earns its place with no redundant entries in this range.

Completeness4/5

The full forward lifecycle (find, install, status, list, use) is covered cleanly. The notable gap is the absence of any uninstall/remove or update operation, which an agent might need to manage installed state, but core workflows are workable.

Maintenance

ActivityMaintained
ResponsivenessWithin a week

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    A
    maintenance
    Enables MCP clients such as Claude Desktop, Cline, and Cursor to extract information from GitHub repositories, including repository summaries, project directory structure, and file contents. It exposes these capabilities as tools that can be invoked directly from a natural-language chat session.
    -
  • F
    license
    Not graded
    quality
    A
    maintenance
    Enables MCP clients such as Claude Desktop, Cline, and Cursor to quickly extract information about GitHub repositories, including repository summaries, project directory structures, and file contents.
    -