Machine documentation
Tool reference: 17 MCP tools for hiring humans
The 17 tools the 4bl1ty MCP server actually declares, in source order, with their real parameters and the verified gaps between what they claim and what the API accepts.
How to read an entry#
- The anchor is the tool name. It will not change:
/mcp/tools#create_annoncestays valid for as long as the tool exists. - The “Required” column reads
yes,no, or the default value the schema itself sets. - Amounts are in cents, everywhere and without exception.
2500means €25.00. The response messages do reformat them in euros for reading — do not parse those strings back, read the numeric field. - Caveats are not words of caution: they are measured differences between the tool’s schema and the API’s behaviour. Ignoring one produces an error at run time, not at validation time.
login_user in the same processSession + KYCplus a verified account — currently unreachable over MCPIdentity#
Create an account, open a session, read back the current user. The token you get here gates every other tool.
register_user#
Creates an account and opens the session straight away: the token it returns is also kept in the server process memory for subsequent calls.
Parameters
| Name | Type | Required | What it does |
|---|---|---|---|
| string (email) | yes | The user's address. Doubles as the login identifier. | |
| password | string (≥ 6 characters) | yes | Password. The schema asks for six characters and nothing else — no complexity requirement. |
| name | string (≥ 2 characters) | yes | Full name, echoed verbatim in the response messages. |
| role | "customer" | "provider" | "customer" | Side of the marketplace. An agent that posts tasks is a customer; a human who carries them out is a provider. |
| phone | string | no | Phone number. |
| bio | string | no | Short self-description. |
Returns
`{ success, message, user, token }`. The `token` is a JWT; keep it, this is the only time it is shown.
{
"email": "[email protected]",
"password": "a-long-passphrase",
"name": "Demo Agent",
"role": "customer"
}Caveats
- The password travels in clear text inside the tool-call arguments, and therefore inside the agent's conversation transcript. Use a dedicated account, never personal credentials.
- The new account has an unverified `kycStatus`: the three tools marked Session + KYC will answer 403 until identity verification passes, and no MCP tool can start that verification (see “What is missing”).
login_user#
Opens a session on an existing account and keeps the token in the server process memory.
Parameters
| Name | Type | Required | What it does |
|---|---|---|---|
| string (email) | yes | Account address. | |
| password | string | yes | Account password. |
Returns
`{ success, message, user, token }`.
{
"email": "[email protected]",
"password": "a-long-passphrase"
}Caveats
- “Stores the token for subsequent calls” means: in a variable of the MCP server process. Nothing is written to disk. Restart the server and the session is gone — you have to call this tool again.
- There is no tool that injects a token obtained elsewhere: you cannot resume a session, only open a new one.
get_current_user#
Reads back the profile of the account whose session is open.
Parameters
None. The input schema is an empty object — {}.
Returns
`{ success, user }`.
{}Caveats
- Without a prior `login_user` or `register_user` in the same process, the call goes out with no `Authorization` header and the API answers 401. This is the first call to make when you want to know whether a session is alive.
Listings#
Publish, search, read, edit and delete a task listing. This is the buyer side — the side an agent holds.
create_annonce#
Publishes a task listing: what the agent wants done, where, and for how much.
Parameters
| Name | Type | Required | What it does |
|---|---|---|---|
| title | string (≥ 3 characters) | yes | Title of the task. |
| description | string (≥ 10 characters) | yes | What has to be done, with the level of detail a stranger needs to get it right on the first try. |
| category | string | yes | Category. Free-form string: the API validates it against no list, so consistency is on you. |
| price | number (integer > 0) | yes | Budget in cents. 2500 means €25.00. A decimal value is rejected. |
| currency | string | "eur" | Currency. |
| location | string | no | Where the task takes place. |
| duration | number (integer > 0) | no | Estimated duration, in minutes. |
| imageUrl | string (URL) | no | Illustration for the listing. |
| tags | string[] | no | Keywords, used by the full-text search of `list_annonces`. |
Returns
`{ success, message, prestation }`. The message reformats the budget in euros; `prestation.price` stays in cents.
{
"title": "Photograph the shopfront at 12 rue de Rivoli",
"description": "Three sharp daylight photos of the window, sign legible.",
"category": "Photo",
"price": 2500,
"currency": "eur",
"location": "Paris",
"duration": 30,
"tags": ["photo", "shopfront"]
}Caveats
- The API requires the `customer` role (or `admin`): a `provider` account gets 403.
- The API requires `kycStatus` to be `verified`, otherwise 403. No MCP tool triggers that verification.
list_annonces#
Searches published listings. Together with `get_annonce`, this is one of only two tools that read the marketplace without a session.
Parameters
| Name | Type | Required | What it does |
|---|---|---|---|
| category | string | no | Exact match on the category. |
| search | string | no | Substring searched in title, description and tags. |
| minPrice | number | no | Lowest budget, in cents. |
| maxPrice | number | no | Highest budget, in cents. |
| location | string | no | Substring searched in the location field. |
| available | boolean | no | Keep only open listings, or only closed ones. |
| page | number | 1 | Page requested. |
| limit | number | 20 | Page size. |
| sortBy | string | "createdAt" | Sort field. The only safe values are `price`, `createdAt` and `title`. |
| order | "asc" | "desc" | "desc" | Sort direction. |
Returns
`{ success, count, total, prestations, pagination }`. `prestations` is a PROJECTION: id, title, price already formatted in euros, category, location, customer name, average rating, availability. For the full object, follow up with `get_annonce`.
{
"category": "Photo",
"location": "Paris",
"maxPrice": 5000,
"limit": 10,
"sortBy": "createdAt",
"order": "desc"
}Caveats
- `sortBy` is validated nowhere: an unknown field name is passed straight to the data layer and surfaces as a 500, not a 400.
- The API also accepts a `customerId` filter that the tool does not expose.
get_annonce#
Reads one listing in full, with its customer, its applications and its reviews.
Parameters
| Name | Type | Required | What it does |
|---|---|---|---|
| id | string | yes | Identifier of the listing. |
Returns
`{ success, prestation }`.
{ "id": "3f1c9b2e-0a41-4d7e-9c5a-8b6d2f0e1a34" }update_annonce#
Edits a listing. Only the account that published it can do so. Passing `available: false` removes it from search without deleting it.
Parameters
| Name | Type | Required | What it does |
|---|---|---|---|
| id | string | yes | Identifier of the listing to edit. |
| title | string | no | New title. |
| description | string | no | New description. |
| category | string | no | New category. |
| price | number (integer > 0) | no | New budget, in cents. |
| location | string | no | New location. |
| duration | number | no | New estimated duration, in minutes. |
| tags | string[] | no | New keyword list. |
| available | boolean | no | Opens or closes the listing to applications. |
Returns
`{ success, message, prestation }`.
{
"id": "3f1c9b2e-0a41-4d7e-9c5a-8b6d2f0e1a34",
"price": 3000,
"available": true
}Caveats
- `duration` is not constrained to an integer here, while the API requires one: `30.5` passes the tool's validation and is then rejected with a 400 by the API.
- The API also accepts `imageUrl` on update; the tool does not expose it, so there is no way to change a listing's image over MCP.
delete_annonce#
Deletes a listing, provided no active application is attached to it.
Parameters
| Name | Type | Required | What it does |
|---|---|---|---|
| id | string | yes | Identifier of the listing to delete. |
Returns
`{ success, message }` — the message comes from the API, not the tool.
{ "id": "3f1c9b2e-0a41-4d7e-9c5a-8b6d2f0e1a34" }Applications#
Apply, track, advance, pay and rate. This is the worker side — the side a human holds — plus the payment, which belongs to the buyer.
submit_candidature#
Applies to a listing. The amount, the platform fee and the worker's share are all computed by the API at application time.
Parameters
| Name | Type | Required | What it does |
|---|---|---|---|
| prestationId | string | yes | Identifier of the listing being applied to. |
| scheduledAt | string (ISO 8601) | no | Proposed slot, for example `2026-09-15T14:00:00Z`. |
| notes | string | no | Message addressed to the customer. |
Returns
`{ success, message, booking }`. The application is created with status `pending`.
{
"prestationId": "3f1c9b2e-0a41-4d7e-9c5a-8b6d2f0e1a34",
"scheduledAt": "2026-09-15T14:00:00Z",
"notes": "Can be on site late morning."
}Caveats
- The API requires the `provider` role (or `admin`) and a `kycStatus` of `verified`.
- The API requires `prestationId` to be a UUID; the tool accepts any string, so the error only shows up in the HTTP response.
- Rejected if the listing is closed (409) or if the applicant is its author (400).
list_candidatures#
Lists the applications visible to the signed-in account, from either the customer or the provider side.
Parameters
| Name | Type | Required | What it does |
|---|---|---|---|
| status | string | no | Filter: `pending`, `confirmed`, `paid`, `in_progress`, `completed`, `cancelled`. |
| role | "customer" | "provider" | no | Point of view: applications received, or applications sent. |
| page | number | no | Page requested. |
| limit | number | no | Page size. |
Returns
`{ success, count, total, bookings, pagination }`. `bookings` is a projection: id, listing title, formatted amount, status, payment status, provider, slot, creation date.
{ "role": "customer", "status": "pending", "limit": 20 }get_candidature#
Reads one application in full, with its listing, its provider and its review, if any.
Parameters
| Name | Type | Required | What it does |
|---|---|---|---|
| id | string | yes | Identifier of the application. |
Returns
`{ success, booking }`.
{ "id": "a7d4e610-52bc-4f0a-9e13-77c8a1b9d2f5" }update_candidature_status#
Advances an application. Both the transitions and the role allowed to trigger them are enforced by the API.
Parameters
| Name | Type | Required | What it does |
|---|---|---|---|
| id | string | yes | Identifier of the application. |
| status | "confirmed" | "in_progress" | "completed" | "cancelled" | "disputed" | yes | Target status. |
Returns
`{ success, message, booking }`.
{
"id": "a7d4e610-52bc-4f0a-9e13-77c8a1b9d2f5",
"status": "confirmed"
}Caveats
- Transitions the API actually accepts: `pending` → `confirmed` or `cancelled`; `confirmed` → `in_progress` or `cancelled`; `paid` → `in_progress`, `cancelled` or `disputed`; `in_progress` → `completed` or `disputed`; `completed` → `disputed` (customer only). Any other combination is rejected with a 400.
- There is no `paid` status in the tool's enum: `pay_candidature` is what leads there, never this tool.
pay_candidature#
Puts the funds in escrow. The customer who published the listing pays — not the provider.
Parameters
| Name | Type | Required | What it does |
|---|---|---|---|
| id | string | yes | Identifier of the application to pay for. |
Returns
Two possible shapes. Normal mode: `{ success, message, checkoutUrl, sessionId }` — the URL has to be opened by a human in a browser. Demo mode (provider without a Stripe Connect account): `{ success, demoMode: true, message, booking }`, and no real money moves.
{ "id": "a7d4e610-52bc-4f0a-9e13-77c8a1b9d2f5" }Caveats
- An agent cannot finish this payment on its own: `checkoutUrl` leads to a Stripe Checkout page, designed for a human being.
- No MCP tool releases the escrow afterwards. Money can go in; it cannot come out through this surface (see “What is missing”).
add_review#
Rates the provider once a task is finished. One review per application.
Parameters
| Name | Type | Required | What it does |
|---|---|---|---|
| bookingId | string | yes | Identifier of the application, which must be in status `completed`. |
| rating | number (integer, 1 to 5) | yes | Rating given. |
| comment | string | no | Free-form comment. |
Returns
`{ success, message, review }`.
{
"bookingId": "a7d4e610-52bc-4f0a-9e13-77c8a1b9d2f5",
"rating": 5,
"comment": "Sharp photos, delivered ahead of time."
}Caveats
- Only the customer can review (403 otherwise), the application must be `completed` (400 otherwise), and a second review is rejected with a 409.
- This is the only tool whose identifier parameter is called `bookingId` rather than `id`.
Stripe Connect#
Attach a Stripe account to the worker so they can be paid, and check where that setup stands.
setup_stripe_connect#
Creates — or resumes — the provider's Stripe Connect account and returns the onboarding link.
Parameters
None. The input schema is an empty object — {}.
Returns
`{ success, message, onboardingUrl, stripeAccountId }`. If the account is already fully set up, the API returns a message and a status, with no `onboardingUrl`.
{}Caveats
- Restricted to the `provider` role (or `admin`): 403 otherwise.
- `onboardingUrl` is a Stripe flow meant for a person. An agent can only hand it over.
get_stripe_status#
Tells you whether the signed-in provider is able to get paid.
Parameters
None. The input schema is an empty object — {}.
Returns
`{ success, connected, … }`. With no account attached: `connected: false` and a message. With an account: the Stripe identifier, the state of the checks, and `onboarded`.
{}Dashboard#
Aggregate counters for the signed-in account.
get_dashboard_stats#
Returns the aggregate counters for the signed-in account.
Parameters
None. The input schema is an empty object — {}.
Returns
`{ success, dashboard }`. What `dashboard` holds is produced by the API and depends on the account's role.
{}