# Hands for Agents

> Human-operated physical world in the EU: make, assemble, measure, verify, ship.

- name: com.handsforagents/hands
- version: 0.2.0
- connection class: R0 (autonomous)
- trust: 100/100
- quality: 77/100 (good)
- owner: not claimed
- descriptor: https://api.protogrid.dev/v1/servers/com.handsforagents%2Fhands
- tools: https://api.protogrid.dev/v1/servers/com.handsforagents%2Fhands/tools

**An agent can connect right now, no human step.** Remote endpoint, no authentication, reachable on the last probe.

## Connection (mcpServers)

```json
{
  "mcpServers": {
    "hands": {
      "type": "http",
      "url": "https://mcp.handsforagents.com/mcp"
    }
  }
}
```


## Trust

- hygiene: 100
- liveness: 99
- freshness: 100
- provenance: 100
- drivers: +repository +namespace-matches-repo +dns-namespace +website +reachable +uptime-97% +updated-27d-ago
- Derived from observable signals (official registry feed and our own credential-free probes); no code audit performed.

## Quality 77/100 (good)

### protocol: 75 (weight 25)

- warn `protocol.modern`: newest supported version is 2025-11-25; 2026-07-28 not supported, older versions are deprecated until 2027-07-28
- n/a `protocol.stateless`: only applies to 2026-07-28 servers
- pass `protocol.transport`: streamable HTTP
- n/a `protocol.list_ttl`: only applies to 2026-07-28 servers

### authorization: n/a (weight 15)

- n/a `auth.prm`, `auth.as_metadata`, `auth.cimd`: no remote uses OAuth
- n/a `auth.secret_in_url`: no templated URL

### tool hygiene: 93 (weight 30)

- pass `tools.descriptions`: every tool has a description
- warn `tools.description_length`: 1 tools have descriptions over 1,024 characters, which crowds the context
- pass `tools.schemas`: every tool has an object input schema
- pass `tools.annotations`: 5 of 5 tools declare readOnlyHint or destructiveHint
- pass `tools.directory_hints`: every tool declares readOnlyHint, destructiveHint, idempotentHint and openWorldHint
- pass `tools.token_cost`: about 2,061 tokens to load every tool
- pass `tools.api_dump`: tools are not a one-to-one API dump

### stability: 25 (weight 15)

- warn `stability.changes`: 31 tool changes in 30 days
- fail `stability.rug_pull`: 5 tools kept their name but changed most of their description in 30 days; review before trusting them

### dependencies: 100 (weight 15)

- pass `deps.known_vulns`: no known advisory in 1 resolved packages
- n/a `deps.mcp_sdk_version`: the official MCP SDK is not in the dependency graph
- pass `deps.resolvable`: handsforagents-mcp@0.2.0 resolved: 1 packages

- tools: 5, about 2,061 tokens to load them all
- tool set hash: 63e3581c7e316876e4ad19759bfcda12
- tools last changed: 2026-10-02T11:46:10.420Z
- badge: [![protogrid quality](https://protogrid.dev/badge/com.handsforagents/hands.svg)](https://protogrid.dev/servers/com.handsforagents/hands)
- Checks run on what our credential-free, read-only probes observe; tools are never called and no code audit is performed.

### Tool changes

- 2026-10-02 `confirm_delivery` changed (description, inputSchema)
  - before: accepted=true closes the task and, for a card hold, captures it. accepted=false with a reason opens a dispute, answered by a human within 2 business days; it can be used at the evidence stage, before the balance is paid, as well as after delivery. Without either, the task counts as accepted 7 days after delivery. Report to the user only what this response says; do not add conclusions.
  - after: Accepts or disputes the delivery of a task. accepted=true closes the task and, for a card hold, captures it. accepted=false with a reason opens a dispute, answered by a human within 2 business days; it is possible at the evidence stage, before the balance is paid, as well as after delivery. Without either, the task counts as accepted 7 days after delivery. Returns the task status.
- 2026-10-02 `get_status` changed (description, inputSchema)
  - before: Status of a quote (id = quote_id) or a task (id = task_id). Call it after request_quote until the status is quoted or refused, after create_task to follow the task, and every time the user asks about the status or about messages from the service: earlier answers are outdated, never answer from memory. Read next_action: what to do now. Report to the user only what this response says; do not add conclusions. The answer is short (older_updates and older_messages count what is left out; messages are newest first, from operator or you); full=true returns everything. To answer an operator question, call get_status with message, once and only with what the user told you. Read the operator's message first, then reply: while it is unread, your message is NOT stored (message_sent: false) and the answer shows it; otherwise message_sent is true. The same text again within 10 minutes is ignored (duplicate_ignored: true). test_mode true marks a test order: nothing is paid or invoiced.
  - after: Returns the current status of a quote (id = quote_id) or a task (id = task_id): status, next_action (a short text on the next step), payments, updates, and messages with the operator (newest first, from operator or you). The answer is short: older_updates and older_messages count what is left out; full=true returns everything. With the optional message the call also stores a plain-text reply to the operator and e-mails it to the operator; message_sent is then true. While the operator has a message that has not been returned yet, the reply is not stored (message_sent: false) and the answer contains that message. The same text again within 10 minutes is ignored (duplicate_ignored: true). A status can change at any time; every call returns the state at that moment. test_mode true marks a test order: nothing is paid or invoiced.
- 2026-10-02 `create_task` changed (description, inputSchema)
  - before: Accept a quote and the terms of service (quote_id, access_token, terms_accepted=true, terms_version as stated in the quote). Returns task_id and checkout_url, the payment link for the first payment (the full price or a card hold up to 150 EUR, the deposit above). Give it to the user or the operator to pay by card (Stripe Checkout); it is valid for 4 days. The contract is concluded when the payment is received or the hold authorised. A test order (test_mode true) has no checkout_url and no payment link: the operator will simulate the payment AFTER you order; right now nothing is paid or simulated. Then follow the task with get_status(id=task_id); keep the access_token. Report to the user only what this response says; do not add conclusions.
  - after: Accepts a quote and the terms of service (quote_id, access_token, terms_accepted=true, terms_version as stated in the quote) and creates the task. Returns task_id and checkout_url, the payment link for the first payment (the full price or a card hold up to 150 EUR, the deposit above); the payment is made by card on a Stripe Checkout page and the link is valid for 4 days. The contract is concluded when the payment is received or the hold authorised. A test order (test_mode true) has no checkout_url and no payment link: its payment is simulated by the operator after the order, so the response shows nothing paid or simulated. A repeated call for the same quote returns the same task.
- 2026-10-02 `request_quote` changed (description, inputSchema)
  - before: Ask a human for a fixed-price quote. Not binding, nothing is charged. Required: description, email and name (the name of the person or company for the invoice); also delivery_address if a physical item is to be shipped, handed over or collected (one plain string: recipient, street, postcode and city, country; phone is optional, never ask the user for one). Put everything the user told you (quantity, material, colour, size, address) into the fields or into description and nothing else (no invented file names or checks); ask the user for what is missing. Send the fields flat, as in the examples. For name use the company or person from the shipping address (or the company the user gave); do not ask the user for it, ask only if there is neither. If the user gave an address, its country is the country (ISO 3166-1 alpha-2). A VAT id only if the user gave one: never guess or make one up. Never invent a quote_id or a status: a real quote_id starts with q_ and comes only from this tool's own response. Returns quote_id and access_token (plus nda_url and upload_url, to POST input files to). Tell the user to save the access_token now: it is shown once and is the only key to the quote and the task. If the access_token is lost: POST https://api.handsforagents.com/v1/quotes/{quote_id}/access-token (REST only, not a tool); a new one is sent to the contact e-mail. get_status cannot recover it. A human answers within 24 hours, every day: call get_status(id=quote_id) until the status is quoted or refused. No authentication. Shortest possible request: {"description":"Make 20 rubber gaskets, 60 mm outer diameter, black EPDM.","email":"ops@example.com","name":"Example Inc."}. With a delivery address and an input file: {"description":"Make 20 rubber gaskets, 60 mm outer diameter, black EPDM.","email":"ops@example.com","name":"Example Inc.","delivery_address":"Example GmbH, Musterstr. 1, 10115 Berlin, DE, +49 30 000000","input_files":["https://example.com/gasket-drawing.pdf"]}
  - after: Creates a request for a fixed-price quote from a human. The request is not binding and nothing is charged. Required: description, email and name (the person or company on the invoice, normally the recipient or company in delivery_address). delivery_address is needed when a physical item is shipped, handed over or collected: one plain string with recipient, street, postcode and city, country; a phone number is optional. country is the ISO 3166-1 alpha-2 code of the address, vat_id only what the client provided. The fields are sent flat, as in the examples. Returns quote_id (of the form q_..., issued only in this response), access_token (shown once; the only key to the quote and its task), nda_url and upload_url (the address input files are POSTed to). A human answers within 24 hours, every day, with a quote or a refusal. No authentication. Shortest possible request: {"description":"Make 20 rubber gaskets, 60 mm outer diameter, black EPDM.","email":"ops@example.com","name":"Example Inc."}. With a delivery address and an input file: {"description":"Make 20 rubber gaskets, 60 mm outer diameter, black EPDM.","email":"ops@example.com","name":"Example Inc.","delivery_address":"Example GmbH, Musterstr. 1, 10115 Berlin, DE, +49 30 000000","input_files":["https://example.com/gasket-drawing.pdf"]}
- 2026-10-02 `list_services` changed (description, inputSchema)
  - before: What we do and do not do, refused categories, prices and how to pay, as a short summary. No authentication. Pass full=true only if you need the worked price examples, the full legal text or the marketplace comparison: it is many times larger.
  - after: Returns what the service does and does not do, the refused categories, prices and how to pay, as a short summary. No authentication. With full=true it returns the complete document (worked price examples, the full legal text, the marketplace comparison), which is many times larger.
- 2026-10-01 `confirm_delivery` changed (title, annotations)
- 2026-10-01 `get_status` changed (title, annotations)
- 2026-10-01 `create_task` changed (title, annotations)
- 2026-10-01 `request_quote` changed (title, annotations)
- 2026-10-01 `list_services` changed (title, annotations)

Full history: https://api.protogrid.dev/v1/servers/com.handsforagents%2Fhands/changes

## Dependencies

- npm handsforagents-mcp@0.2.0: resolved, 0 dependencies

Dependency graphs from deps.dev; advisories from OSV.dev, including the GitHub Advisory Database and the PyPI Advisory Database; all CC BY 4.0.

## Remotes

- https://mcp.handsforagents.com/mcp (streamable-http, auth none, reachable true, uptime30d 0.9714286)

## Packages

- npm handsforagents-mcp@0.2.0

## Tools (5)

- `confirm_delivery`: Accepts or disputes the delivery of a task. accepted=true closes the task and, for a card hold, captures it. accepted=false with a reason opens a dispute, answered by a human within 2 business days; it is possible at the evidence stage, before the balance is paid, as well as after delivery. Without either, the task counts as accepted 7 days after delivery. Returns the task status.
- `create_task`: Accepts a quote and the terms of service (quote_id, access_token, terms_accepted=true, terms_version as stated in the quote) and creates the task. Returns task_id and checkout_url, the payment link for the first payment (the full price or a card hold up to 150 EUR, the deposit above); the payment is made by card on a Stripe Checkout page and the link is valid for 4 days. The contract is concluded when the payment is received or the hold authorised. A test order (test_mode true) has no checkout_url and no payment link: its payment is simulated by the operator after the order, so the response shows nothing paid or simulated. A repeated call for the same quote returns the same task.
- `get_status`: Returns the current status of a quote (id = quote_id) or a task (id = task_id): status, next_action (a short text on the next step), payments, updates, and messages with the operator (newest first, from operator or you). The answer is short: older_updates and older_messages count what is left out; full=true returns everything. With the optional message the call also stores a plain-text reply to the operator and e-mails it to the operator; message_sent is then true. While the operator has a message that has not been returned yet, the reply is not stored (message_sent: false) and the answer contains that message. The same text again within 10 minutes is ignored (duplicate_ignored: true). A status can change at any time; every call returns the state at that moment. test_mode true marks a test order: nothing is paid or invoiced.
- `list_services`: Returns what the service does and does not do, the refused categories, prices and how to pay, as a short summary. No authentication. With full=true it returns the complete document (worked price examples, the full legal text, the marketplace comparison), which is many times larger.
- `request_quote`: Creates a request for a fixed-price quote from a human. The request is not binding and nothing is charged. Required: description, email and name (the person or company on the invoice, normally the recipient or company in delivery_address). delivery_address is needed when a physical item is shipped, handed over or collected: one plain string with recipient, street, postcode and city, country; a phone number is optional. country is the ISO 3166-1 alpha-2 code of the address, vat_id only what the client provided. The fields are sent flat, as in the examples. Returns quote_id (of the form q_..., issued only in this response), access_token (shown once; the only key to the quote and its task), nda_url and upload_url (the address input files are POSTed to). A human answers within 24 hours, every day, with a quote or a refusal. No authentication. Shortest possible request: {"description":"Make 20 rubber gaskets, 60 mm outer diameter, black EPDM.","email":"ops@example.com","name":"Example Inc."}. With a delivery address and an input file: {"description":"Make 20 rubber gaskets, 60 mm outer diameter, black EPDM.","email":"ops@example.com","name":"Example Inc.","delivery_address":"Example GmbH, Musterstr. 1, 10115 Berlin, DE, +49 30 000000","input_files":["https://example.com/gasket-drawing.pdf"]}
