Skip to main content
Glama
README.md
# handwork

Some jobs need a person in the physical world: something made,
measured, assembled, tested, or shipped. handwork is a small MCP
server that connects an agent to a human service desk that takes
on exactly that kind of work. It exposes three tools — a service
catalogue, a quote request, and a status lookup — and forwards
each call to the desk's public remote endpoint, returning the
answer unchanged.

Asking for a quote is not placing an order. Nothing is charged
and nothing is made until a quote comes back by e-mail and is
accepted there; the tools themselves carry no ordering or
payment capability.

## Tools

- `list_services` — what the service will and will not do, the
  categories it refuses, example prices, how payment works, and
  the key contract terms. Takes no arguments and needs no
  authentication.
- `request_quote` — describe a physical-world task (what is to
  be done, which services it needs, deliverables, deadline,
  delivery address, input files, currency) along with the
  client's invoice details, and a human screens it and replies
  with a fixed-price quote by e-mail within 24 hours. The reply
  carries a `quote_id` and an `access_token`; keep the token,
  it is the only way to read the request back. No field at the
  top level is required, but the nested `task` object requires a
  `description` and the nested `client` object requires `email`
  and `name`.
- `get_status` — the state of an earlier quote request. Both
  `id` (the `quote_id`) and `access_token` are required. Records
  are kept for 90 days, and the quote itself arrives by e-mail.

## How it works

handwork is a forwarding client, not a reimplementation. It
serves `tools/list` itself, from the tool definitions the remote
publishes, and for every `tools/call` it opens a streamable-HTTP
JSON-RPC session with the upstream — `initialize`, then
`notifications/initialized`, then the call, carrying the
`Mcp-Session-Id` header whenever the upstream issues one — and
passes the upstream result through verbatim. If the upstream
cannot be reached or answers with an error, the call fails with
a `handwork error:` message instead of a fabricated result.

The upstream endpoint defaults to `https://handsforagents.com/mcp`.
Setting the `HANDS_MCP_URL` environment variable points the
client at a different endpoint (a reconstruction affordance; the
published service itself names no override).

## Run it

As an MCP server over stdio:

```bash
npx -y @reneturcios/handwork mcp
```

MCP client configuration:

```json
{
  "mcpServers": {
    "handwork": {
      "command": "npx",
      "args": ["-y", "@reneturcios/handwork", "mcp"]
    }
  }
}
```

In a container (the default command is `mcp`):

```bash
docker run -i ghcr.io/cloudcorprecords/handwork
docker run --rm ghcr.io/cloudcorprecords/handwork --version
```

## CLI

```bash
handwork mcp          # serve the tools over stdio
handwork --version    # print the version
```

Any other subcommand prints usage and exits with code 2.

## Development

```bash
npm install
npm run build   # tsc -> dist/
npm test        # node test runner via tsx; stubbed upstream, no network
npm run dev     # run the CLI from source
```

The tests drive the forwarding core against a fake JSON-RPC
upstream injected in place of fetch, covering the handshake
order, session handling, verbatim pass-through, event-stream
responses, error surfacing, and a check that the served
`tools/list` matches the captured upstream surface exactly.

## License

MIT — see `LICENSE`.