agenthand 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agenthand-0.1.0/.env.example +16 -0
- agenthand-0.1.0/.gitignore +21 -0
- agenthand-0.1.0/CHANGELOG.md +45 -0
- agenthand-0.1.0/PKG-INFO +193 -0
- agenthand-0.1.0/README.md +174 -0
- agenthand-0.1.0/pyproject.toml +65 -0
- agenthand-0.1.0/server.json +1 -0
- agenthand-0.1.0/src/agenthand/__init__.py +8 -0
- agenthand-0.1.0/src/agenthand/assets.py +402 -0
- agenthand-0.1.0/src/agenthand/composite.py +930 -0
- agenthand-0.1.0/src/agenthand/config.py +142 -0
- agenthand-0.1.0/src/agenthand/ingest.py +142 -0
- agenthand-0.1.0/src/agenthand/ledger.py +167 -0
- agenthand-0.1.0/src/agenthand/measure.py +1165 -0
- agenthand-0.1.0/src/agenthand/meta_client.py +1152 -0
- agenthand-0.1.0/src/agenthand/pricing.py +109 -0
- agenthand-0.1.0/src/agenthand/sam_masks.py +155 -0
- agenthand-0.1.0/src/agenthand/segmentation.py +339 -0
- agenthand-0.1.0/src/agenthand/server.py +728 -0
- agenthand-0.1.0/src/agenthand/verify.py +160 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# agenthand environment - copy to .env and fill in locally.
|
|
2
|
+
# Placeholder NAMES only. Never commit a real .env file.
|
|
3
|
+
|
|
4
|
+
# Meta Model API key (server-side only; a dedicated judge key is used for
|
|
5
|
+
# judged traffic - never put either in source control)
|
|
6
|
+
META_API_KEY=
|
|
7
|
+
|
|
8
|
+
# Local data directory: asset store + JSONL cost ledger live here.
|
|
9
|
+
# Defaults to ./data under the project root when unset.
|
|
10
|
+
AGENTHAND_DATA_DIR=
|
|
11
|
+
|
|
12
|
+
# Fail-closed total spend cap in USD across ALL billable model calls.
|
|
13
|
+
# Calls refuse before they run if they would push the ledger past this.
|
|
14
|
+
# Default when unset: 120.00 working cap. This variable may only LOWER
|
|
15
|
+
# the cap; values above the 150.00 hard ceiling are clamped to it.
|
|
16
|
+
AGENTHAND_TOTAL_SPEND_CAP_USD=120.00
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Secrets - never commit real credentials
|
|
2
|
+
.env
|
|
3
|
+
.env.*
|
|
4
|
+
!.env.example
|
|
5
|
+
*.key
|
|
6
|
+
*.pem
|
|
7
|
+
|
|
8
|
+
# Python
|
|
9
|
+
__pycache__/
|
|
10
|
+
*.py[cod]
|
|
11
|
+
*.egg-info/
|
|
12
|
+
build/
|
|
13
|
+
dist/
|
|
14
|
+
.venv/
|
|
15
|
+
.pytest_cache/
|
|
16
|
+
|
|
17
|
+
# agenthand runtime data (asset store + cost ledger live here)
|
|
18
|
+
data/
|
|
19
|
+
|
|
20
|
+
# OS noise
|
|
21
|
+
.DS_Store
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to agenthand are recorded here. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/), and the project uses
|
|
5
|
+
semantic versioning.
|
|
6
|
+
|
|
7
|
+
## [0.1.0] - 2026-10-27
|
|
8
|
+
|
|
9
|
+
First public release. agenthand is an MCP server (stdio transport) that
|
|
10
|
+
gives AI agents three tools for turning a seller's messy product photos
|
|
11
|
+
into listing-ready material. The seller never opens it; their agent
|
|
12
|
+
calls it.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- `identify` — reads a photo and plans the listing shot: a structured
|
|
17
|
+
description of the item, the cut-out concept with alternates, a
|
|
18
|
+
suggested title, listing bullets, and condition notes.
|
|
19
|
+
- `cut_out` — cuts the product out of its photo and returns a
|
|
20
|
+
transparent PNG behind an `asset://` handle. The mask is
|
|
21
|
+
quality-checked, with one bounded retry on a poor mask, and the
|
|
22
|
+
result includes a mask review (bounding box, fill, frame-edge
|
|
23
|
+
contact, warnings).
|
|
24
|
+
- `draw` (Fidelity Lock) — stages the real product into a generated
|
|
25
|
+
scene without regenerating the product. The stored foreground is
|
|
26
|
+
composited untouched onto a generated background plate, and the
|
|
27
|
+
result ships with a fidelity receipt: hashes for the source photo,
|
|
28
|
+
the foreground, and the mask, plus the changed-pixel count measured
|
|
29
|
+
on the delivered file. The receipt also states what the count
|
|
30
|
+
excluded.
|
|
31
|
+
- `agenthand-verify` — a standalone checker that re-derives a fidelity
|
|
32
|
+
receipt from the files on disk, and can verify an exported
|
|
33
|
+
source/final/mask triple with no server involved. It passes only on
|
|
34
|
+
exactly zero changed pixels with real coverage.
|
|
35
|
+
- One billing choke point for every model call: reserve-then-settle
|
|
36
|
+
accounting against a local ledger, a fail-closed spend cap, and a
|
|
37
|
+
cost receipt per call. A response with no usable usage settles at
|
|
38
|
+
its reserved projection rather than $0, and an unpriced model raises
|
|
39
|
+
instead of estimating.
|
|
40
|
+
- Ingest by asset handle, http(s) URL, or base64 data URI, with size
|
|
41
|
+
caps, EXIF orientation applied, and HEIC support. Colour profiles
|
|
42
|
+
are preserved end to end and recorded on the receipt.
|
|
43
|
+
- Images chain between tools as `asset://` handles instead of bytes,
|
|
44
|
+
and every asset is readable by the client as an MCP resource at its
|
|
45
|
+
own URI.
|
agenthand-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: agenthand
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: agenthand: an MCP server that gives AI sales agents three production tools - identify, cut_out, draw - for turning messy product photos into listing-ready images.
|
|
5
|
+
Author: Daniel Wagner
|
|
6
|
+
License: Proprietary
|
|
7
|
+
Requires-Python: >=3.12
|
|
8
|
+
Requires-Dist: mcp<3,>=2.0
|
|
9
|
+
Requires-Dist: meta-sam-parser<0.2,>=0.1.0
|
|
10
|
+
Requires-Dist: numpy<3,>=1.26
|
|
11
|
+
Requires-Dist: openai<4,>=1.66
|
|
12
|
+
Requires-Dist: opencv-python-headless<6,>=4.8
|
|
13
|
+
Requires-Dist: pillow-heif<2,>=1.8
|
|
14
|
+
Requires-Dist: pillow<14,>=10
|
|
15
|
+
Provides-Extra: dev
|
|
16
|
+
Requires-Dist: hypothesis<7,>=6; extra == 'dev'
|
|
17
|
+
Requires-Dist: pytest<10,>=8; extra == 'dev'
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
|
|
20
|
+
# agenthand
|
|
21
|
+
|
|
22
|
+
<p align="center">
|
|
23
|
+
<img src="assets/logo-rotating-v2.gif" alt="agenthand logo: a robot hand presenting three rotating arcs, framed by registration brackets" width="420">
|
|
24
|
+
</p>
|
|
25
|
+
|
|
26
|
+
An MCP server for AI agents that help people sell things.
|
|
27
|
+
|
|
28
|
+
The seller never opens agenthand. Their agent calls it. A seller hands their
|
|
29
|
+
agent a messy product photo; agenthand turns it into listing-ready material
|
|
30
|
+
through three tools, in the order a listing is produced:
|
|
31
|
+
|
|
32
|
+
| Tool | What it does |
|
|
33
|
+
|---|---|
|
|
34
|
+
| `draw` | Places the real product, pixel-untouched, into a generated scene (a chair in a regal room, a game lot on a clean table) and returns the composite with a fidelity receipt. |
|
|
35
|
+
| `cut_out` | Segments the product out of its photo and returns a transparent PNG, referenced by an asset handle. The concept is optional; without one, the planning step runs internally. |
|
|
36
|
+
| `identify` | The planning step inside the chain: reads a photo and plans the cut, returning a structured description plus the segmentation-ready noun-phrase concept (with alternates) that `cut_out` consumes. |
|
|
37
|
+
|
|
38
|
+
## Fidelity Lock
|
|
39
|
+
|
|
40
|
+
`draw` never regenerates the product. The invariant, enforced in code:
|
|
41
|
+
|
|
42
|
+
1. Segmentation extracts the real product foreground and its mask.
|
|
43
|
+
2. The product layer is stored untouched, with hashes recorded for the
|
|
44
|
+
source, the foreground, and the mask: both the file-byte hash and the
|
|
45
|
+
decoded-pixel hash of each.
|
|
46
|
+
3. The image model generates ONLY the background scene plate. Its
|
|
47
|
+
interface takes a prompt and dimensions, never product pixels.
|
|
48
|
+
4. Deterministic code composites the original product layer onto that
|
|
49
|
+
plate. The plate is resized and cropped to the product's dimensions;
|
|
50
|
+
the product layer is never scaled.
|
|
51
|
+
5. `draw` refuses anything that is not a `foreground_png` asset chained
|
|
52
|
+
back to a source photo, and verifies the stored hashes before a single
|
|
53
|
+
pixel moves.
|
|
54
|
+
6. The result ships with a fidelity receipt: source, foreground, and mask
|
|
55
|
+
hashes, the delivered file's own hashes, the transformations applied,
|
|
56
|
+
the measured count of changed opaque foreground pixels, the model
|
|
57
|
+
calls made, and their cost. The receipt also publishes what the count
|
|
58
|
+
excluded: the edge-band pixel count and its maximum width, the opaque
|
|
59
|
+
share of the mask, the exact changed-pixel predicate with tolerance 0,
|
|
60
|
+
and the colour-profile identity of the source photo and the composite
|
|
61
|
+
(a dropped or changed ICC profile recolours the product while pixel
|
|
62
|
+
values stay identical, so it is recorded and counted as a fidelity
|
|
63
|
+
failure).
|
|
64
|
+
|
|
65
|
+
The claim is precise: the stored extracted foreground reached the
|
|
66
|
+
composite unchanged, and its hashes pin exactly which layer that was.
|
|
67
|
+
Edge-band pixels (partially transparent) blend with the plate during
|
|
68
|
+
compositing; the receipt counts them separately instead of overclaiming.
|
|
69
|
+
The receipt's counts are measured on the delivered file, decoded back
|
|
70
|
+
from the store, and can be re-derived independently:
|
|
71
|
+
`composite.verify_receipt_from_disk` recounts from the stored files,
|
|
72
|
+
checks the receipt's own hashes against the assets it names, and
|
|
73
|
+
passes only on exactly zero changed pixels with real coverage; the
|
|
74
|
+
standalone `agenthand-verify SOURCE FINAL MASK` checker verifies
|
|
75
|
+
exported files with no store at all and likewise refuses a mask that
|
|
76
|
+
selects nothing. Ingest accepts the
|
|
77
|
+
formats phones produce, including HEIC, and preserves each photo's
|
|
78
|
+
embedded colour profile end to end.
|
|
79
|
+
|
|
80
|
+
A bounded mask-recovery loop guards `cut_out`: the mask is quality-checked,
|
|
81
|
+
and on a poor mask the tool retries once with an alternate concept phrase
|
|
82
|
+
from the planning step. Every attempt is traced in the receipt.
|
|
83
|
+
|
|
84
|
+
## Asset handles
|
|
85
|
+
|
|
86
|
+
Tools never pass image bytes back and forth. Every image is stored locally
|
|
87
|
+
(with a per-asset sidecar record, written atomically) and referenced as
|
|
88
|
+
`asset://<id>`. Handles chain between tools: `identify` reads one,
|
|
89
|
+
`cut_out` returns a new one, `draw` consumes it.
|
|
90
|
+
|
|
91
|
+
Photos get in through ingest: a tool's image argument may be an existing
|
|
92
|
+
handle, an http(s) URL, or a base64 data URI. Ingest caps the byte and
|
|
93
|
+
pixel size, applies EXIF orientation, and normalizes to 8-bit RGBA PNG.
|
|
94
|
+
Images get out two ways: `draw` returns an image preview with its result,
|
|
95
|
+
and every asset is readable by the client as the MCP resource at its own
|
|
96
|
+
`asset://<id>` URI.
|
|
97
|
+
|
|
98
|
+
## Cost receipts and the spend cap
|
|
99
|
+
|
|
100
|
+
Every billable call flows through one choke point
|
|
101
|
+
(`src/agenthand/meta_client.py`) using reserve-then-settle accounting:
|
|
102
|
+
under a file lock, the projected worst-case cost is checked against the
|
|
103
|
+
ledger and reserved as a pending receipt; after the call, a settlement
|
|
104
|
+
receipt records the actual cost priced from the provider's usage counts.
|
|
105
|
+
If a call fails after it may have billed, the reservation stays counted.
|
|
106
|
+
A call whose provider response carries no usable usage settles at its
|
|
107
|
+
reserved projection rather than $0: missing usage never erases spend.
|
|
108
|
+
Receipts land in a local JSONL ledger with tool, model, token and image
|
|
109
|
+
counts, USD estimate, and the pricing-table version used. Prices live in
|
|
110
|
+
one module (`src/agenthand/pricing.py`) so a price change is a one-line
|
|
111
|
+
edit with a version bump; an unpriced model raises rather than estimating
|
|
112
|
+
as $0. Every spend path shares the one ledger — the dry-run gate
|
|
113
|
+
included (its asset store is isolated in a temp dir, its ledger is not).
|
|
114
|
+
|
|
115
|
+
The server is fail-closed on spend. The working cap defaults to
|
|
116
|
+
**$120.00**; configuration may move it up or down but never past the
|
|
117
|
+
hard ceiling of **$150.00** (the hackathon credit amount), which no
|
|
118
|
+
configuration can exceed. Corrupt, negative, or non-finite ledger
|
|
119
|
+
entries refuse all spend: unknown spend state means no spend.
|
|
120
|
+
|
|
121
|
+
## Status
|
|
122
|
+
|
|
123
|
+
Hackathon build (Meta Global AI Developer Hackathon, Oct 26 - Nov 4,
|
|
124
|
+
2026). All three tools are wired to the real Meta Model API through the
|
|
125
|
+
spend-cap billing choke point — `identify` to muse-spark-1.3, `cut_out`
|
|
126
|
+
to sam-3.1, `draw` to muse-image-1.0 — and the full chain has run live
|
|
127
|
+
end to end. The verified run of 2026-10-26 (identify $0.007544,
|
|
128
|
+
cut_out $0.0025, draw $0.01; 580,613 opaque pixels checked, 0 changed)
|
|
129
|
+
is published with its fidelity receipt on the
|
|
130
|
+
[project site](https://ausernameforyou.github.io/agenthand/#fidelity),
|
|
131
|
+
where the same check can be re-run in the browser against the run's own
|
|
132
|
+
files. The placeholder plate survives only behind an explicit dev flag
|
|
133
|
+
for offline tests. Today the server runs locally over stdio; a hosted
|
|
134
|
+
endpoint comes later.
|
|
135
|
+
|
|
136
|
+
The server also exists as a single-binary Rust build (source in the
|
|
137
|
+
`agenthand-rust` repository). It passed a parity gate against the frozen
|
|
138
|
+
files of the verified run above, reproducing the run's counts and its
|
|
139
|
+
output pixel hash, and a live run from the Rust binary was cross-checked
|
|
140
|
+
by the Python verifier. The Python implementation remains the
|
|
141
|
+
reference; the Rust build is a second implementation of the same
|
|
142
|
+
server, and the two agree.
|
|
143
|
+
|
|
144
|
+
## Run it
|
|
145
|
+
|
|
146
|
+
Register agenthand with any MCP client. The primary route uses
|
|
147
|
+
[uv](https://docs.astral.sh/uv/): nothing to install ahead of time, uv
|
|
148
|
+
fetches the published package and runs it.
|
|
149
|
+
|
|
150
|
+
```json
|
|
151
|
+
{
|
|
152
|
+
"mcpServers": {
|
|
153
|
+
"agenthand": {
|
|
154
|
+
"command": "uvx",
|
|
155
|
+
"args": ["agenthand"],
|
|
156
|
+
"env": { "META_API_KEY": "…" }
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Or install the package with pip and point the client at the installed
|
|
163
|
+
command:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
pip install agenthand
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
```json
|
|
170
|
+
{
|
|
171
|
+
"mcpServers": {
|
|
172
|
+
"agenthand": {
|
|
173
|
+
"command": "agenthand",
|
|
174
|
+
"env": { "META_API_KEY": "…" }
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
The server starts and lists its tools without a key; the key is only
|
|
181
|
+
needed when a tool makes a model call. Configuration is by environment
|
|
182
|
+
variable; see `.env.example`.
|
|
183
|
+
|
|
184
|
+
### From source (dev)
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
git clone https://github.com/AUsernameForYou/agenthand
|
|
188
|
+
cd agenthand
|
|
189
|
+
python3.12 -m venv .venv
|
|
190
|
+
.venv/bin/pip install -e ".[dev]"
|
|
191
|
+
.venv/bin/agenthand # stdio transport
|
|
192
|
+
.venv/bin/pytest # unit tests
|
|
193
|
+
```
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# agenthand
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="assets/logo-rotating-v2.gif" alt="agenthand logo: a robot hand presenting three rotating arcs, framed by registration brackets" width="420">
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
An MCP server for AI agents that help people sell things.
|
|
8
|
+
|
|
9
|
+
The seller never opens agenthand. Their agent calls it. A seller hands their
|
|
10
|
+
agent a messy product photo; agenthand turns it into listing-ready material
|
|
11
|
+
through three tools, in the order a listing is produced:
|
|
12
|
+
|
|
13
|
+
| Tool | What it does |
|
|
14
|
+
|---|---|
|
|
15
|
+
| `draw` | Places the real product, pixel-untouched, into a generated scene (a chair in a regal room, a game lot on a clean table) and returns the composite with a fidelity receipt. |
|
|
16
|
+
| `cut_out` | Segments the product out of its photo and returns a transparent PNG, referenced by an asset handle. The concept is optional; without one, the planning step runs internally. |
|
|
17
|
+
| `identify` | The planning step inside the chain: reads a photo and plans the cut, returning a structured description plus the segmentation-ready noun-phrase concept (with alternates) that `cut_out` consumes. |
|
|
18
|
+
|
|
19
|
+
## Fidelity Lock
|
|
20
|
+
|
|
21
|
+
`draw` never regenerates the product. The invariant, enforced in code:
|
|
22
|
+
|
|
23
|
+
1. Segmentation extracts the real product foreground and its mask.
|
|
24
|
+
2. The product layer is stored untouched, with hashes recorded for the
|
|
25
|
+
source, the foreground, and the mask: both the file-byte hash and the
|
|
26
|
+
decoded-pixel hash of each.
|
|
27
|
+
3. The image model generates ONLY the background scene plate. Its
|
|
28
|
+
interface takes a prompt and dimensions, never product pixels.
|
|
29
|
+
4. Deterministic code composites the original product layer onto that
|
|
30
|
+
plate. The plate is resized and cropped to the product's dimensions;
|
|
31
|
+
the product layer is never scaled.
|
|
32
|
+
5. `draw` refuses anything that is not a `foreground_png` asset chained
|
|
33
|
+
back to a source photo, and verifies the stored hashes before a single
|
|
34
|
+
pixel moves.
|
|
35
|
+
6. The result ships with a fidelity receipt: source, foreground, and mask
|
|
36
|
+
hashes, the delivered file's own hashes, the transformations applied,
|
|
37
|
+
the measured count of changed opaque foreground pixels, the model
|
|
38
|
+
calls made, and their cost. The receipt also publishes what the count
|
|
39
|
+
excluded: the edge-band pixel count and its maximum width, the opaque
|
|
40
|
+
share of the mask, the exact changed-pixel predicate with tolerance 0,
|
|
41
|
+
and the colour-profile identity of the source photo and the composite
|
|
42
|
+
(a dropped or changed ICC profile recolours the product while pixel
|
|
43
|
+
values stay identical, so it is recorded and counted as a fidelity
|
|
44
|
+
failure).
|
|
45
|
+
|
|
46
|
+
The claim is precise: the stored extracted foreground reached the
|
|
47
|
+
composite unchanged, and its hashes pin exactly which layer that was.
|
|
48
|
+
Edge-band pixels (partially transparent) blend with the plate during
|
|
49
|
+
compositing; the receipt counts them separately instead of overclaiming.
|
|
50
|
+
The receipt's counts are measured on the delivered file, decoded back
|
|
51
|
+
from the store, and can be re-derived independently:
|
|
52
|
+
`composite.verify_receipt_from_disk` recounts from the stored files,
|
|
53
|
+
checks the receipt's own hashes against the assets it names, and
|
|
54
|
+
passes only on exactly zero changed pixels with real coverage; the
|
|
55
|
+
standalone `agenthand-verify SOURCE FINAL MASK` checker verifies
|
|
56
|
+
exported files with no store at all and likewise refuses a mask that
|
|
57
|
+
selects nothing. Ingest accepts the
|
|
58
|
+
formats phones produce, including HEIC, and preserves each photo's
|
|
59
|
+
embedded colour profile end to end.
|
|
60
|
+
|
|
61
|
+
A bounded mask-recovery loop guards `cut_out`: the mask is quality-checked,
|
|
62
|
+
and on a poor mask the tool retries once with an alternate concept phrase
|
|
63
|
+
from the planning step. Every attempt is traced in the receipt.
|
|
64
|
+
|
|
65
|
+
## Asset handles
|
|
66
|
+
|
|
67
|
+
Tools never pass image bytes back and forth. Every image is stored locally
|
|
68
|
+
(with a per-asset sidecar record, written atomically) and referenced as
|
|
69
|
+
`asset://<id>`. Handles chain between tools: `identify` reads one,
|
|
70
|
+
`cut_out` returns a new one, `draw` consumes it.
|
|
71
|
+
|
|
72
|
+
Photos get in through ingest: a tool's image argument may be an existing
|
|
73
|
+
handle, an http(s) URL, or a base64 data URI. Ingest caps the byte and
|
|
74
|
+
pixel size, applies EXIF orientation, and normalizes to 8-bit RGBA PNG.
|
|
75
|
+
Images get out two ways: `draw` returns an image preview with its result,
|
|
76
|
+
and every asset is readable by the client as the MCP resource at its own
|
|
77
|
+
`asset://<id>` URI.
|
|
78
|
+
|
|
79
|
+
## Cost receipts and the spend cap
|
|
80
|
+
|
|
81
|
+
Every billable call flows through one choke point
|
|
82
|
+
(`src/agenthand/meta_client.py`) using reserve-then-settle accounting:
|
|
83
|
+
under a file lock, the projected worst-case cost is checked against the
|
|
84
|
+
ledger and reserved as a pending receipt; after the call, a settlement
|
|
85
|
+
receipt records the actual cost priced from the provider's usage counts.
|
|
86
|
+
If a call fails after it may have billed, the reservation stays counted.
|
|
87
|
+
A call whose provider response carries no usable usage settles at its
|
|
88
|
+
reserved projection rather than $0: missing usage never erases spend.
|
|
89
|
+
Receipts land in a local JSONL ledger with tool, model, token and image
|
|
90
|
+
counts, USD estimate, and the pricing-table version used. Prices live in
|
|
91
|
+
one module (`src/agenthand/pricing.py`) so a price change is a one-line
|
|
92
|
+
edit with a version bump; an unpriced model raises rather than estimating
|
|
93
|
+
as $0. Every spend path shares the one ledger — the dry-run gate
|
|
94
|
+
included (its asset store is isolated in a temp dir, its ledger is not).
|
|
95
|
+
|
|
96
|
+
The server is fail-closed on spend. The working cap defaults to
|
|
97
|
+
**$120.00**; configuration may move it up or down but never past the
|
|
98
|
+
hard ceiling of **$150.00** (the hackathon credit amount), which no
|
|
99
|
+
configuration can exceed. Corrupt, negative, or non-finite ledger
|
|
100
|
+
entries refuse all spend: unknown spend state means no spend.
|
|
101
|
+
|
|
102
|
+
## Status
|
|
103
|
+
|
|
104
|
+
Hackathon build (Meta Global AI Developer Hackathon, Oct 26 - Nov 4,
|
|
105
|
+
2026). All three tools are wired to the real Meta Model API through the
|
|
106
|
+
spend-cap billing choke point — `identify` to muse-spark-1.3, `cut_out`
|
|
107
|
+
to sam-3.1, `draw` to muse-image-1.0 — and the full chain has run live
|
|
108
|
+
end to end. The verified run of 2026-10-26 (identify $0.007544,
|
|
109
|
+
cut_out $0.0025, draw $0.01; 580,613 opaque pixels checked, 0 changed)
|
|
110
|
+
is published with its fidelity receipt on the
|
|
111
|
+
[project site](https://ausernameforyou.github.io/agenthand/#fidelity),
|
|
112
|
+
where the same check can be re-run in the browser against the run's own
|
|
113
|
+
files. The placeholder plate survives only behind an explicit dev flag
|
|
114
|
+
for offline tests. Today the server runs locally over stdio; a hosted
|
|
115
|
+
endpoint comes later.
|
|
116
|
+
|
|
117
|
+
The server also exists as a single-binary Rust build (source in the
|
|
118
|
+
`agenthand-rust` repository). It passed a parity gate against the frozen
|
|
119
|
+
files of the verified run above, reproducing the run's counts and its
|
|
120
|
+
output pixel hash, and a live run from the Rust binary was cross-checked
|
|
121
|
+
by the Python verifier. The Python implementation remains the
|
|
122
|
+
reference; the Rust build is a second implementation of the same
|
|
123
|
+
server, and the two agree.
|
|
124
|
+
|
|
125
|
+
## Run it
|
|
126
|
+
|
|
127
|
+
Register agenthand with any MCP client. The primary route uses
|
|
128
|
+
[uv](https://docs.astral.sh/uv/): nothing to install ahead of time, uv
|
|
129
|
+
fetches the published package and runs it.
|
|
130
|
+
|
|
131
|
+
```json
|
|
132
|
+
{
|
|
133
|
+
"mcpServers": {
|
|
134
|
+
"agenthand": {
|
|
135
|
+
"command": "uvx",
|
|
136
|
+
"args": ["agenthand"],
|
|
137
|
+
"env": { "META_API_KEY": "…" }
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Or install the package with pip and point the client at the installed
|
|
144
|
+
command:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
pip install agenthand
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
```json
|
|
151
|
+
{
|
|
152
|
+
"mcpServers": {
|
|
153
|
+
"agenthand": {
|
|
154
|
+
"command": "agenthand",
|
|
155
|
+
"env": { "META_API_KEY": "…" }
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
The server starts and lists its tools without a key; the key is only
|
|
162
|
+
needed when a tool makes a model call. Configuration is by environment
|
|
163
|
+
variable; see `.env.example`.
|
|
164
|
+
|
|
165
|
+
### From source (dev)
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
git clone https://github.com/AUsernameForYou/agenthand
|
|
169
|
+
cd agenthand
|
|
170
|
+
python3.12 -m venv .venv
|
|
171
|
+
.venv/bin/pip install -e ".[dev]"
|
|
172
|
+
.venv/bin/agenthand # stdio transport
|
|
173
|
+
.venv/bin/pytest # unit tests
|
|
174
|
+
```
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "agenthand"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "agenthand: an MCP server that gives AI sales agents three production tools - identify, cut_out, draw - for turning messy product photos into listing-ready images."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.12"
|
|
11
|
+
license = { text = "Proprietary" }
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Daniel Wagner" },
|
|
14
|
+
]
|
|
15
|
+
# Pinned as floor + next-major ceiling: the floor is the oldest
|
|
16
|
+
# version the suite is verified against (or the first version with
|
|
17
|
+
# an API we call), the ceiling keeps a future major release from
|
|
18
|
+
# being installed untested. Verified set at pin time (2026-10-27):
|
|
19
|
+
# mcp 2.3.0, openai 3.39.0, Pillow 13.0.0, pillow-heif 1.8.1,
|
|
20
|
+
# meta-sam-parser 0.1.0, numpy 2.5.4, opencv-python-headless 5.0.0.93.
|
|
21
|
+
dependencies = [
|
|
22
|
+
"mcp>=2.0,<3",
|
|
23
|
+
# Floor is the first release line with the Responses API
|
|
24
|
+
# (meta_client.segment_image calls client.responses.create).
|
|
25
|
+
"openai>=1.66,<4",
|
|
26
|
+
"Pillow>=10,<14",
|
|
27
|
+
"pillow-heif>=1.8,<2",
|
|
28
|
+
"meta-sam-parser>=0.1.0,<0.2",
|
|
29
|
+
# measure.py (prototype estimator): classical CV + array math.
|
|
30
|
+
# composite.py / segmentation.py use numpy + cv2 for the
|
|
31
|
+
# fidelity counting and mask analysis hot paths.
|
|
32
|
+
"numpy>=1.26,<3",
|
|
33
|
+
"opencv-python-headless>=4.8,<6",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[project.optional-dependencies]
|
|
37
|
+
dev = [
|
|
38
|
+
"pytest>=8,<10",
|
|
39
|
+
# Property-based tests for the verifier/compositor counting
|
|
40
|
+
# core (tests/test_fidelity_properties.py).
|
|
41
|
+
"hypothesis>=6,<7",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[project.scripts]
|
|
45
|
+
agenthand = "agenthand.server:main"
|
|
46
|
+
agenthand-verify = "agenthand.verify:main"
|
|
47
|
+
|
|
48
|
+
[tool.hatch.build.targets.wheel]
|
|
49
|
+
packages = ["src/agenthand"]
|
|
50
|
+
|
|
51
|
+
# Keep the source distribution focused on installable source and release
|
|
52
|
+
# metadata. The website images, test suite, and local build scripts are
|
|
53
|
+
# development artifacts and would otherwise add roughly 14 MB to the sdist.
|
|
54
|
+
[tool.hatch.build.targets.sdist]
|
|
55
|
+
exclude = [
|
|
56
|
+
"/.github",
|
|
57
|
+
"/assets",
|
|
58
|
+
"/docs",
|
|
59
|
+
"/scripts",
|
|
60
|
+
"/tests",
|
|
61
|
+
"/BUILD_LOG.md",
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
[tool.pytest.ini_options]
|
|
65
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"$schema":"https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json","description":"Turn messy product photos into listing-ready images, with a fidelity receipt on every staged shot.","name":"io.github.AUsernameForYou/agenthand","packages":[{"environmentVariables":[{"description":"Meta Model API key. The server starts and lists its tools without one; the key is required when a tool makes a model call.","format":"string","isRequired":true,"isSecret":true,"name":"META_API_KEY"}],"identifier":"agenthand","registryBaseUrl":"https://pypi.org","registryType":"pypi","runtimeHint":"uvx","transport":{"type":"stdio"},"version":"0.1.0"}],"repository":{"source":"github","url":"https://github.com/AUsernameForYou/agenthand"},"title":"agenthand","version":"0.1.0"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""agenthand: an MCP server giving AI sales agents identify / cut_out / draw.
|
|
2
|
+
|
|
3
|
+
The seller never opens agenthand; their agent calls it. Tools exchange
|
|
4
|
+
asset handles (asset://<id>) instead of image bytes, every call writes a
|
|
5
|
+
cost receipt, and billable spend is fail-closed behind a hard cap.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
__version__ = "0.1.0"
|