Skip to main content
Glama
cotletdev

PeoplePerHour MCP Server

PeoplePerHour API and MCP server, self-hosted

A PeoplePerHour API and a PeoplePerHour MCP server you run on your own computer, in Python, on the session of your own Google Chrome. The same 17 PeoplePerHour tools we run in production at Cotlet: search open projects and read full briefs, search freelancers and Offers and read profiles with recent reviews, keep a project watchlist and saved searches with email alerts, see median budgets per category, and read your own posted projects, notifications and WorkStreams.

PeoplePerHour has no public API and no official MCP server. This repo gives you both:

  • MCP server for Claude Code, Claude Desktop, Cursor, Codex and any MCP client, over stdio or HTTP. Setup

  • REST API on http://127.0.0.1:8787/api/v1/peopleperhour, with OpenAPI docs at /docs. Setup

  • Python: call("search_projects", query="web design"), plus 9 ready scripts in examples/.

13 tools read. The other 4 change only your own watchlist and saved searches. Nothing here sends a proposal or a message, posts a project, buys an Offer or pays, and no Proposal credit is spent.

It is for technical people who want to run it themselves, for noncommercial use only (license). If you want it running 24/7 on a server, kept working when PeoplePerHour changes its site, for a team or a business, use the hosted version at cotlet.dev.

PeoplePerHour MCP server Python 3.11+ License: PolyForm Noncommercial 1.0.0

git clone https://github.com/cotletdev/peopleperhour-api-mcp-server.git && cd peopleperhour-api-mcp-server
python3 -m venv .venv && . .venv/bin/activate && pip install -e .
peopleperhour-mcp connect                          # reads your PeoplePerHour session from Chrome
peopleperhour-mcp call search_projects query="web design" limit=5
claude mcp add peopleperhour -- "$PWD/.venv/bin/peopleperhour-mcp" mcp

Contents

Related MCP server: Upwork MCP Server

How it works

AI agent (MCP) / script (REST, Python) ──▶ peopleperhour-mcp on your computer ──your cookies──▶ www.peopleperhour.com
                                                    ▲
                      peopleperhour-mcp connect ────┘ reads them once from your Chrome (DevTools Protocol)
  1. You sign in to PeoplePerHour in your own Chrome, the way you always do. Tick Remember me.

  2. peopleperhour-mcp connect attaches to that Chrome through the Chrome DevTools Protocol, reads the peopleperhour.com cookies and saves them to ~/.config/peopleperhour-api-mcp/session.json, readable by your user only. It never sees or stores your password.

  3. Every tool call is a request to the JSON API the PeoplePerHour site itself calls (www.peopleperhour.com/v2/...) with those cookies, sent with curl_cffi, which copies Chrome's TLS fingerprint. No headless browser runs.

The session lives in the api cookie, about 100 days after a sign-in with Remember me. When PeoplePerHour signs you out, the server reads the cookies from Chrome again, if Chrome is open with remote debugging on.

Requirements

  • Python 3.11 or newer.

  • Google Chrome 144 or newer, signed in to PeoplePerHour. Any Chrome or Chromium works with a debugging port.

  • macOS, Linux or Windows.

  • Any PeoplePerHour account. A free buyer account is enough for all 17 tools.

Install

git clone https://github.com/cotletdev/peopleperhour-api-mcp-server.git
cd peopleperhour-api-mcp-server
python3 -m venv .venv
. .venv/bin/activate              # Windows: .venv\Scripts\activate
pip install -e .
peopleperhour-mcp --version

With uv: uv venv && uv pip install -e ., then uv run peopleperhour-mcp ....

Setting it up with an AI agent (Claude Code, Codex, Cursor)? Open it in this folder and ask it to set up the repo: AGENTS.md tells it every step, and it asks you only for the steps in Chrome.

To update: git pull && pip install -e .. We copy every change of the hosted PeoplePerHour tools into this repo.

Connect your Chrome

  1. Open chrome://inspect/#remote-debugging in Chrome and switch remote debugging on. Chrome then accepts DevTools connections from programs on this computer, and asks you before each one.

  2. Make sure you are signed in at peopleperhour.com.

  3. Run:

    peopleperhour-mcp connect
  4. Chrome asks whether to allow the connection. Click Allow.

Saved 9 PeoplePerHour cookies to /Users/you/.config/peopleperhour-api-mcp/session.json
Signed in to PeoplePerHour as Maya Reed (maya@yourname.com)

You can switch remote debugging off again afterwards. Leave it on if you want the server to pick up a new session by itself after PeoplePerHour signs you out.

connect looks for Chrome's DevToolsActivePort file in the default profile folder. For Chrome Beta, Canary or a custom profile folder, pass --profile-dir "<folder>".

Option B: a Chrome with a debugging port

Chrome does not open a debugging port on your default profile, so start a separate one, sign in to PeoplePerHour there once, and connect to it:

# macOS
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --remote-debugging-port=9222 --user-data-dir="$HOME/.chrome-pph"
# Linux
google-chrome --remote-debugging-port=9222 --user-data-dir="$HOME/.chrome-pph"
# Windows
"C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222 --user-data-dir="%USERPROFILE%\.chrome-pph"

peopleperhour-mcp connect --cdp http://127.0.0.1:9222

--cdp also takes a ws:// DevTools URL, for example of a Chrome on another machine reached over an SSH tunnel.

For a server with no Chrome: in Chrome open DevTools on peopleperhour.com, Application > Cookies > https://www.peopleperhour.com, copy the value of api, then:

peopleperhour-mcp connect --token          # paste it, input is hidden
# or, without a session file:
export PEOPLEPERHOUR_AUTH_TOKEN=...

A pasted token is not refreshed on its own. Paste a new one when PeoplePerHour signs you out.

Check the session at any time:

peopleperhour-mcp status

MCP server

The MCP server lists all 17 tools with their input schemas and a description written for agents. The 13 read tools are marked read-only; --read-only hides the 4 that change your watchlist and saved searches.

Claude Code

claude mcp add peopleperhour -- /path/to/peopleperhour-api-mcp-server/.venv/bin/peopleperhour-mcp mcp

Claude Desktop

~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):

{
  "mcpServers": {
    "peopleperhour": {
      "command": "/path/to/peopleperhour-api-mcp-server/.venv/bin/peopleperhour-mcp",
      "args": ["mcp"]
    }
  }
}

Cursor

~/.cursor/mcp.json, the same block as Claude Desktop. A ready copy is in mcp.json.

Codex

~/.codex/config.toml:

[mcp_servers.peopleperhour]
command = "/path/to/peopleperhour-api-mcp-server/.venv/bin/peopleperhour-mcp"
args = ["mcp"]

Over HTTP

peopleperhour-mcp serve also serves MCP over streamable HTTP at http://127.0.0.1:8787/mcp, for clients that take a URL:

peopleperhour-mcp serve
claude mcp add --transport http peopleperhour http://127.0.0.1:8787/mcp

Then ask your agent things like:

Check PeoplePerHour for web design projects posted since yesterday, skip anything under £200 or with more than 15 proposals, read the briefs of the rest and give me a shortlist of five.

Read the brief of project 4527712, open the files the buyer attached, list what I must deliver and the questions I have to answer, and draft a proposal I can paste.

Is project 4527712 still open, and how many proposals does it have now?

Find logo designers rated 80% or more at £10 to £30 an hour, read the profiles and recent reviews of the top five, and tell me which three to contact.

Save a search for urgent fixed-price design projects called "Urgent design" with a daily email.

REST API

peopleperhour-mcp serve                    # http://127.0.0.1:8787, MCP at /mcp, docs at /docs

Each tool has its own route under /api/v1/peopleperhour, the same paths as the hosted API at cotlet.dev, so code written against one works with the other. Path parts and the query string are arguments.

curl 'http://127.0.0.1:8787/api/v1/peopleperhour/projects/search?query=web%20design&since=2026-10-21T07:00:00Z&limit=20'
curl 'http://127.0.0.1:8787/api/v1/peopleperhour/projects/4527712'
curl 'http://127.0.0.1:8787/api/v1/peopleperhour/freelancers/search?query=logo%20design&min_rating=80'
curl -X PUT 'http://127.0.0.1:8787/api/v1/peopleperhour/projects/4527712/watch'

Any tool by name, body as its arguments:

curl -X POST http://127.0.0.1:8787/api/v1/peopleperhour/tools/search_projects -d '{"category": "design", "limit": 10}'
  • GET /api/v1/peopleperhour/tools: every tool with its route, input schema and an example answer.

  • GET /docs: interactive OpenAPI docs, GET /openapi.json the schema, for n8n, Postman or a generated client.

  • Answers are JSON. List tools return next_cursor; pass it back as cursor for the next page.

The server listens on 127.0.0.1 only. To reach it from another device of yours, set a token, and every request then needs Authorization: Bearer <token>:

PEOPLEPERHOUR_MCP_TOKEN=$(openssl rand -hex 24) peopleperhour-mcp serve --host 0.0.0.0

Python and the example scripts

Straight from Python, no server needed:

from peopleperhour_api_mcp import call
from peopleperhour_api_mcp.scripting import paginate, write_rows

new = list(paginate("search_projects", {"query": "logo", "since": "2026-10-21T00:00:00Z"}, "projects"))
write_rows(new, "projects.csv")
brief = call("get_project", project_id=new[0]["project_id"])["brief"]

Or one tool from the shell: peopleperhour-mcp call get_project project_id=4527712, or with a JSON object.

Ready scripts in examples/, one per job on the integration page. Each takes --help, and the list scripts take --out file.csv or --out file.json:

Script

What it does

find_new_projects.py

New projects for one or more keywords in the last N hours, merged, cut on --min-budget (or --hourly-rate) and --max-proposals, then the full brief, questions and files of each one left.

read_project_brief.py

One project before you write a proposal: brief, attached files, the buyer's questions, proposals, expiry and the 80% price floor.

watch_urgent_projects.py

Urgent projects in a category with fewer than N proposals. --state remembers the last run, for an hourly cron job.

check_project_open.py

Whether projects are still open and how many proposals each has now.

shortlist_freelancers.py

Freelancers for a skill, cut on rate band and rating, with each profile's stats and the average of its latest reviews.

compare_offers.py

The top Offers for a job side by side: price, delivery days, sales, add-ons and what the seller needs from you.

save_project_alert.py

Save a project search with filters and a daily or instant email alert, then list your saved searches.

buyer_daily_digest.py

For a buyer: your open projects with proposal counts, unread notifications and WorkStreams with unread messages.

median_budgets.py

Median fixed and hourly budgets per freelancer level for the categories you name, in GBP, USD or EUR.

python examples/find_new_projects.py --query "web design" --query webflow --hours 24 --min-budget 200 --max-proposals 15
python examples/read_project_brief.py 4527712
python examples/shortlist_freelancers.py "logo design" --hourly-rate 10-30 --min-rating 80
python examples/median_budgets.py translation --currency USD

On a schedule, cron on your own computer works while it is on: 0 * * * * cd ~/peopleperhour-api-mcp-server && .venv/bin/python examples/watch_urgent_projects.py --category design --state urgent.json.

Budgets are compared as PeoplePerHour gives them, in the buyer's currency (GBP, EUR or USD), so a floor of 200 means 200 of whatever the buyer picked.

All 17 tools

peopleperhour-mcp tools prints this list, peopleperhour-mcp tools --json adds the input schemas. Times are UTC.

Projects

Tool

Access

REST route

What it does

search_projects

read

GET /projects/search

Open projects buyers posted, newest first, with budget, category, proposals and the brief's start.

get_project

read

GET /projects/{project_id}

One project's full brief with budget, attachments, interview questions, buyer and proposal count.

list_my_projects

read

GET /projects/mine

Projects this account posted as a buyer, with status, budget and proposal count.

Watchlist

Tool

Access

REST route

What it does

watch_project

write

PUT /projects/{project_id}/watch

Add a project to this account's watchlist (Favourite Jobs) to come back to it later.

unwatch_project

write

DELETE /projects/{project_id}/watch

Take a project off this account's watchlist.

list_watchlist

read

GET /projects/watched

Open projects on this account's watchlist (Favourite Jobs), with budget and proposal count.

Saved searches

Tool

Access

REST route

What it does

list_saved_searches

read

GET /saved-searches

This account's saved project searches with their filters and email alert setting.

save_search

write

POST /saved-searches

Save a project search with an email alert, or rename one or change how often it emails.

delete_saved_search

write

DELETE /saved-searches/{saved_search_id}

Delete one of this account's saved project searches and its email alert.

Freelancers

Tool

Access

REST route

What it does

search_freelancers

read

GET /freelancers/search

Freelancers by skill or keyword, with rate, rating, reviews, completed projects and skills.

get_freelancer

read

GET /freelancers/{freelancer_id}

A freelancer's public profile: rate, stats, skills, portfolio and the latest reviews on the page.

Offers

Tool

Access

REST route

What it does

search_offers

read

GET /offers/search

Fixed-price Offers freelancers sell, by keyword or price, with sales, rating and seller.

get_offer

read

GET /offers/{offer_id}

One Offer with its full description, what the seller needs from you, prices, add-ons and images.

Account, notifications and WorkStreams

Tool

Access

REST route

What it does

get_account

read

GET /account

The signed-in PeoplePerHour account: name, type, buyer stats, unread messages and favourite counts.

list_notifications

read

GET /notifications

The latest notifications of this account (proposals, messages, project updates) and unread counts.

list_workstreams

read

GET /workstreams

This account's WorkStreams (conversations with hired freelancers) with the last message.

Categories

Tool

Access

REST route

What it does

list_categories

read

GET /categories

The 10 project categories with their subcategories and typical budgets per freelancer level.

since makes polling cheap: an agent passes the time of its last check and reads only what arrived after it. One call with since scans at most the 200 newest projects, so a page can hold fewer than limit and still have a next_cursor.

Budgets, rates and prices come as PeoplePerHour gives them: a project in the buyer's currency, freelancer rates, Offers and median budgets in your account currency or the one you pick.

Not in this version: the freelancer side (proposals, your seller profile, your own Offers), posting or editing projects, sending messages in WorkStreams, accepting proposals, and payments, invoices and Proposal credits.

Never built, on purpose: your PeoplePerHour sign-in, email, password and settings, and anything that moves money (Proposal credits, subscriptions, payments). Every request passes a guard that refuses any change to those PeoplePerHour paths.

Configuration

Variable

Default

What it does

PEOPLEPERHOUR_MCP_HOME

~/.config/peopleperhour-api-mcp

Folder of session.json.

PEOPLEPERHOUR_AUTH_TOKEN

PeoplePerHour api cookie, instead of peopleperhour-mcp connect.

PEOPLEPERHOUR_PROXY

Proxy for every request to PeoplePerHour, e.g. http://user:pass@host:port.

PEOPLEPERHOUR_MCP_READ_ONLY

1 hides and refuses the 4 tools that change PeoplePerHour: watchlist and saved searches (same as --read-only).

PEOPLEPERHOUR_MCP_TOKEN

Bearer token required by serve; needed to listen beyond 127.0.0.1.

PEOPLEPERHOUR_MCP_HOST, PEOPLEPERHOUR_MCP_PORT

127.0.0.1, 8787

Address of serve.

Security and your PeoplePerHour account

  • Your password never reaches this code. Only cookies are read, and only those of peopleperhour.com.

  • The session file is yours. session.json is created with mode 0600. Anyone who has it can act as you on PeoplePerHour, so keep it out of git and shared folders.

  • Local by default. serve binds to 127.0.0.1 and refuses another address without PEOPLEPERHOUR_MCP_TOKEN.

  • peopleperhour.com only. Requests and redirects outside peopleperhour.com are refused. Attachment links point to PeoplePerHour's file host; the server returns them and does not download them.

  • Your own lists only. 13 tools read. The 4 writes change your watchlist and saved searches and nothing else: no proposal, message or Offer purchase goes to anyone. A watched project lists you among its watchers, so unwatch what you no longer follow.

  • Keep the pace human. A cron job every hour is fine. Hundreds of calls a minute is not how a person browses, and you are responsible for what runs in your account.

Errors

The REST API answers {"error": "<code>", "message": "..."}. The MCP server returns the same code and message as a tool error.

Status

Code

What to do

401

auth_required, auth_expired

No session, or PeoplePerHour signed you out. Sign in to PeoplePerHour in Chrome and run peopleperhour-mcp connect.

403

target_blocked

PeoplePerHour refused the request or showed a bot check. Open peopleperhour.com in Chrome once, then retry.

409

captcha_required

PeoplePerHour asks for a CAPTCHA. Solve it in Chrome.

422

invalid_input

An argument is missing or wrong; the message names it.

429

rate_limited

PeoplePerHour is limiting the account. Wait a few minutes.

502

target_error

No such project, freelancer, Offer or saved search, a private or removed one, a filter PeoplePerHour refused (the message gives its reason), or PeoplePerHour answered with an error or changed its site. git pull for the latest tools, or open an issue.

Self-hosted or hosted

This repo

Cotlet, hosted

Tools

the same 17

the same 17

Runs

on your computer, while it is on

in the cloud, 24/7

PeoplePerHour session

your Chrome, cookies in a local file

your own Cloud Browser in the EU, profile encrypted with AES-256-GCM

When PeoplePerHour changes its site

git pull once we have fixed it

fixed for you, every tool tested daily

Works with

MCP clients on your machine, local scripts

Claude.ai and ChatGPT connectors, n8n, Make, Zapier, any HTTP client

Who may use it

you, for noncommercial use

teams, businesses, agencies

Price

free

free 7-day trial with 2,000 credits, no card; then one-time packs from $29 for 5,000 credits

On the hosted version a successful call uses 20 to 30 credits (25 for most tools), failed calls are free, and the Cloud Browser uses 50 credits a day while it has an app enabled for agents. Full pricing.

FAQ

Does PeoplePerHour have an official API? No. PeoplePerHour has no public API, no developer docs and no webhooks (checked 12 Oct 2026). The one built-in alert is Saved Searches: up to 10 searches on the Jobs page, each emailing new results instantly or once a day. PeoplePerHour gives you nothing to call them from code; here save_search and list_saved_searches manage them. Details: cotlet.dev/integrations/peopleperhour-api-mcp-server.

Is there a PeoplePerHour MCP server for Claude, ChatGPT or Cursor? Yes, this one runs on your machine: peopleperhour-mcp mcp for Claude Code, Claude Desktop, Cursor and Codex. ChatGPT and Claude.ai connectors need a public HTTPS URL, which the hosted PeoplePerHour MCP server gives you.

Is this a PeoplePerHour scraper? It returns what people want a job scraper for (new projects with budget, proposals and brief, freelancers and Offers, as JSON or CSV) but runs no headless browser. It calls the same JSON endpoints the PeoplePerHour site calls, in your own account. The one HTML page it reads is a freelancer's profile, for the latest reviews.

Can I get new PeoplePerHour projects as they are posted? Yes. Call search_projects with since set to your last check, from cron or an agent. watch_urgent_projects.py keeps that time in a state file for you.

Can it send proposals or answer buyers? No. Proposals, WorkStream messages, buying Offers, invoices and your Proposal credits are not in this version, and it spends no credits. It can read your WorkStreams and notifications. You write and send proposals and messages on PeoplePerHour yourself.

Can I hire on PeoplePerHour with it? It helps you choose: search_freelancers and get_freelancer for profiles and recent reviews, search_offers and get_offer for fixed-price Offers, list_categories for what buyers usually pay. Posting the project, contacting a freelancer and paying stay on PeoplePerHour.

Do I need a paid PeoplePerHour plan or a freelancer account? No. A free buyer account is enough for all 17 tools.

Does get_project return the project's skills? No, because PeoplePerHour's project data has no list of skills. The skills are in the brief text, which an agent reads.

Why does it need my Chrome? To read your PeoplePerHour session without your password. Chrome is used once per sign-in, not for each call.

What happens when PeoplePerHour signs me out? Calls fail with auth_expired. With Chrome remote debugging on, the server reads the new cookies on the next call (click Allow when Chrome asks); otherwise run peopleperhour-mcp connect again.

Can it run on a VPS or in Docker? Technically yes, with PEOPLEPERHOUR_AUTH_TOKEN. PeoplePerHour then sees your session from a datacenter IP, which looks less like you. For an always-on setup the hosted version keeps your session in your own Cloud Browser on a fixed IP.

Will my PeoplePerHour account get banned? Requests carry Chrome's fingerprint and go out one at a time, and the tools read only what you could open yourself. Nobody can promise a platform never acts. Keep the polling to what a person would do.

Can I use it at work or for my clients? No, the license allows noncommercial use only. For a team, a company or client work, use Cotlet or write to contact@cotlet.dev.

Is it open source? The source is public, the license is not an open source license: noncommercial use only, no business use.

A tool broke or I need another one. Open an issue with the tool name and the error message.

License

PolyForm Noncommercial License 1.0.0. In short:

  • Allowed: noncommercial use: you, for your own personal purposes with your own PeoplePerHour account, or a charity, school, public research or government body. Changing the code, and sharing it under the same license.

  • Not allowed: any commercial use, your own business included; client work; selling or offering it, or a service built on it.


Maintained by Cotlet (@cotletdev). PeoplePerHour is a trademark of its owner. This project is unofficial and not affiliated with, endorsed or sponsored by PeoplePerHour.

Available Tools

17 tools
get_accountGet accountA
Read-onlyIdempotent
Inspect

The signed-in PeoplePerHour account: name, type, buyer stats, unread messages and favourite counts.

Returns the account the tools act as: member id, first name and initial, email, account type (buyer or seller), location, currency, profile URL, unread messages, buyer stats (projects posted, listed and completed, freelancers worked with, share of projects awarded, response time) and how many Offers, freelancers and projects it keeps as favourites or watches.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.2/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true, idempotentHint=true, openWorldHint=true, and destructiveHint=false, so the safety profile is clear. The description adds useful scope by listing sensitive returned data such as email, buyer stats, unread messages, and favourites, but does not disclose additional behavioral traits like authentication requirements or rate limits.

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 front-loaded with a high-level summary followed by a detailed field enumeration. It is appropriately sized, though there is some duplication between the first sentence's mention of buyer stats/unread messages/favourite counts and the second sentence's elaboration of those fields.

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 carries the burden of explaining return values, and it does so thoroughly by enumerating member id, name, email, account type, location, currency, profile URL, unread messages, buyer stats, and favourite/watch counts. With zero parameters and full annotation coverage, the definition is complete enough for correct invocation.

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?

This tool takes zero parameters, so there are no parameter semantics to clarify. The baseline score of 4 applies because the schema has no parameters and the description does not need to compensate for missing parameter documentation.

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?

The description uses a specific verb-resource pairing ('The signed-in PeoplePerHour account') and enumerates the returned fields, so the agent knows exactly what data this tool fetches. It also distinguishes itself from sibling tools like get_freelancer by emphasizing that it returns the account the tools act as, i.e., the current signed-in identity rather than another user.

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?

The description provides clear context for when to use it: retrieving the signed-in account and the identity behind all tool actions. It does not explicitly name alternatives or when-not conditions, but for a zero-parameter self-account read, the practical ambiguity with siblings is low.

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

get_freelancerGet freelancerA
Read-onlyIdempotent
Inspect

A freelancer's public profile: rate, stats, skills, portfolio and the latest reviews on the page.

Returns a freelancer's public profile: short name, job title, location, hourly rate, CERT level, rating in percent, review and project counts, skills, languages, full About text, up to 30 portfolio items, and the reviews the profile page shows (usually the latest few, with the project they came from). reviews is the total count; PeoplePerHour does not let older reviews be paged, so only recent_reviews come with text. Times are UTC. Pass a freelancer_id from search_freelancers or an Offer, or the profile URL.

NameRequiredDescriptionDefault
freelancer_idYesfreelancer_id from search_freelancers or an Offer, or the freelancer's profile URL.

TDQS

A4.4/5.0
Behavior5/5

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

Annotations already cover read-only, idempotent, and open-world safety, and the description adds real behavioral context on top: reviews cannot be paged so only recent_reviews carry text, the reviews field is a total count, portfolio is capped at 30 items, and all times are UTC. These are constraints an agent could not infer from structured fields.

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 opening one-line summary is front-loaded and the detail flows from it, with every clause covering a distinct aspect of the return value. It is slightly redundant, since the lead line and the 'Returns a freelancer's public profile' sentence restate the same scope before getting to specifics.

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 carries the full burden of describing return values, and it does so field-group by field-group including the review-pagination caveat. An agent knows what to expect back and how to interpret the reviews versus recent_reviews distinction.

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 coverage is 100% and the sole parameter's description already explains the accepted ID sources, so the description only restates that same information. A baseline 3 is appropriate since the schema does the heavy lifting and the description adds no new format or syntax detail.

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 and resource and enumerates exactly what comes back: rate, CERT level, rating, skills, About text, portfolio items, and reviews. It is clearly the single-profile counterpart to search_freelancers, so an agent can distinguish it from all listed siblings without opening a schema.

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?

Tells the agent where the required identifier comes from (search_freelancers, an Offer, or a profile URL), which is the practical gating condition for calling it. It does not explicitly say when not to use it or name a competing tool for a given scenario, so it falls short of full routing guidance.

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

get_offerGet OfferA
Read-onlyIdempotent
Inspect

One Offer with its full description, what the seller needs from you, prices, add-ons and images.

Returns one Offer as its page shows it: title, price in your account currency and in each currency the seller set, delivery days, sales, rating in percent with the count per star, full description, what the buyer must send, add-ons with their price and extra days, image links and the freelancer who sells it. Pass an offer_id from search_offers or the Offer's URL.

NameRequiredDescriptionDefault
offer_idYesoffer_id from search_offers, or the Offer's page URL.

TDQS

A4.2/5.0
Behavior4/5

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

With readOnlyHint, idempotentHint and openWorldHint already declared, the description adds value by disclosing the return shape in detail: prices in both account and seller currencies, star-count rating breakdown, add-ons with extra days, and image links. It does not mention auth requirements or failure behavior when an offer_id is stale or invalid, which is the main remaining gap.

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 opening sentence is front-loaded and the input instruction sits at the end where an agent looks last for the action step. The return-field enumeration is long and partially restates the opening line, costing a little density but earning its place since there is no output schema.

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, so the description carries the burden of explaining the return payload, and it does so thoroughly across currency, delivery, rating distribution, add-ons and seller identity. For a one-parameter read tool with full annotation coverage, nothing essential 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 the single parameter is already documented in the schema as 'offer_id from search_offers, or the Offer's page URL.' The description repeats that guidance nearly verbatim, adding no new syntax or format detail, 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?

The description names a specific verb and resource ('One Offer with its full description...') and immediately scopes it as a single-record fetch, which cleanly separates it from the sibling search_offers. The enumeration of what 'one Offer' contains makes the object concrete rather than abstract.

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?

'Pass an offer_id from search_offers or the Offer's URL' establishes the retrieval workflow and the valid input provenance. It does not state explicit when-not conditions, but for a single-record getter the alternative (search_offers) is obvious from the naming and the description reinforces it.

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

get_projectGet projectA
Read-onlyIdempotent
Inspect

One project's full brief with budget, attachments, interview questions, buyer and proposal count.

Returns one project as its public page shows it: the buyer's full brief, budget, category, experience level, where it is done, links to the files the buyer attached, the questions the buyer asks in a proposal, how many proposals it has and whether it is still open. client is the buyer's public profile. Times are UTC. Pass a project_id from search_projects or the project's URL.

NameRequiredDescriptionDefault
project_idYesproject_id from search_projects, or the project's page URL.

TDQS

A4/5.0
Behavior4/5

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

Annotations already declare readOnly/idempotent/non-destructive, so the description's job is context, and it delivers: 'as its public page shows it' sets the visibility scope, 'Times are UTC' removes timestamp ambiguity, and 'whether it is still open' flags a status field. It does not say what happens for a deleted or private project_id, which is the remaining gap.

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

Conciseness3/5

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

The lead sentence front-loads the payload well, but the second sentence re-enumerates the same fields (budget, buyer, proposals) at greater length, so a meaningful share of the text is repetition rather than new information.

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

Completeness4/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 carries the return-value burden and does so by listing the returned fields and the UTC time convention. For a one-parameter read tool that is nearly sufficient; only edge-case behavior (missing/closed project) is unaddressed.

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?

Single parameter with 100% schema description coverage, so the schema already defines project_id and its two accepted forms. The description restates the same guidance ('from search_projects or the project's URL') without adding format rules or validation behavior, so 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?

Names a specific verb and resource ('One project's full brief') and enumerates exactly what comes back: budget, attachments, interview questions, buyer, proposal count. The reference to pulling the id from search_projects makes the single-record scope unambiguous against that sibling and list_my_projects.

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?

'Pass a project_id from search_projects or the project's URL' tells the agent both where the identifier comes from and the preceding step in the workflow. It stops short of explicit exclusions (e.g., use list_my_projects for bulk, or what to do when a project is closed), so not a full 5.

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

list_categoriesList categoriesA
Read-onlyIdempotent
Inspect

The 10 project categories with their subcategories and typical budgets per freelancer level.

Returns PeoplePerHour's project categories and their subcategories. category is the slug search_projects and save_search take. median_budget is PeoplePerHour's median project budget in the subcategory, fixed price and hourly, by freelancer level (below level 4, level 4, level 5, Top CERT) and on average, in the currency asked for: a guide when pricing a proposal or a project.

NameRequiredDescriptionDefault
currencyNoCurrency of the median budgets. Default: GBP.

TDQS

A4.5/5.0
Behavior4/5

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

Annotations already declare readOnly, idempotent, non-destructive, open-world, so the safety profile is covered. The description adds real substance beyond that: a bounded result set of 10 categories, budgets broken out by fixed price vs hourly and by the four freelancer levels, and per-currency values — information that matters because no output schema exists. It stops short of noting any rate limits or whether budgets are cached/updated, which keeps it off a 5.

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?

One-line summary sentence up front, followed by a compact expansion that stays on the resource itself. There is no filler, no repeated title restatement, and the most important identity/cardinality fact is front-loaded.

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 carries the burden of explaining return values, and it does: categories, subcategories, and median budgets by pricing model, freelancer level, and currency. Combined with a single optional, fully documented enum parameter and read-only annotations, an agent has everything needed to call 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?

Schema coverage is 100%, so the baseline would be 3, but the description earns above baseline by clarifying that the currency applies to the median budgets and that values are supplied 'in the currency asked for' — reinforcing the enum's meaning and reminding the agent the default is GBP via the schema. It adds interpretation rather than merely restating the property.

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?

The description states a specific resource (PeoplePerHour project categories, subcategories, and median budgets) and its exact cardinality ('The 10 project categories'). It also distinguishes itself from sibling search tools by explaining that 'category is the slug search_projects and save_search take', so an agent can see how it relates to them rather than confusing it with search_projects itself.

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?

It gives a concrete use case ('a guide when pricing a proposal or a project') and positions itself as the reference source whose slugs feed search_projects and save_search. What is missing is an explicit exclusion or sequencing rule (e.g. 'call this before search_projects to resolve a category name'), but the context for when to reach for it is clear.

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

list_my_projectsList my projectsA
Read-onlyIdempotent
Inspect

Projects this account posted as a buyer, with status, budget and proposal count.

Returns the projects the signed-in buyer posted, most recent proposal first, each with its status (open, in_progress, under_moderation, completed and so on), budget, proposal count and the start of the brief. counts is the number of projects per status. Archived projects come back only with status archived. Pass next_cursor back as cursor; it is null on the last page.

NameRequiredDescriptionDefault
queryNoWords in the project title.
cursorNonext_cursor from the previous call.
statusNoOnly projects in this state.

TDQS

A4.4/5.0
Behavior4/5

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

Annotations already cover read-only/idempotent safety, and the description adds real behavior: sort order (most recent proposal first), returned fields per project, the meaning of counts, and the archived filter quirk. It doesn't state result-size limits or whether counts reflect the filtered set, which keeps it off a 5.

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?

Front-loaded with purpose then return shape, then pagination – good ordering with no filler. The second sentence is dense and slightly run-on (status list, fields, counts all in one), costing a little readability.

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?

Despite no output schema, the description documents the return shape (fields, ordering, counts), pagination contract, and the archived edge case. For a 3-param, fully-documented read tool, an agent has everything needed to call 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?

Schema coverage is 100%, so the baseline is 3; the description adds meaning above the schema by explaining cursor comes from next_cursor and null signals the last page, plus the special archived-status behavior. Query parameter is left to the schema, so it's not a full 5.

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 with explicit scope: projects 'the signed-in buyer posted'. That scoping cleanly separates it from sibling search_projects/get_project, which cover broader or single-project retrieval.

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?

Gives concrete operational guidance: 'Archived projects come back only with status archived' and 'Pass next_cursor back as cursor; it is null on the last page.' It lacks an explicit alternative pointer (e.g., use search_projects for other buyers), so it stops short of full when/when-not guidance.

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

list_notificationsList notificationsA
Read-onlyIdempotent
Inspect

The latest notifications of this account (proposals, messages, project updates) and unread counts.

Returns the notifications under the bell on PeoplePerHour, newest first: text, link, whether it was read and when it came. unread counts unread notifications, proposals and WorkStream messages. Reading does not mark anything as read.

NameRequiredDescriptionDefault

No parameters

TDQS

A3.8/5.0
Behavior4/5

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

The annotations already declare this as read-only and idempotent. The description adds useful behavioral context by stating that reading does not mark anything as read, that notifications are returned newest first, and what the unread counts represent.

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 reasonably concise and front-loads the core purpose and unread counts. The second sentence elaborates on returned data and reading behavior without excessive repetition, though it is slightly long.

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

Completeness4/5

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

With no parameters and no output schema, the description needs to explain enough about the result. It does so by naming the returned notification fields and unread-count meaning, making it sufficiently complete for a zero-parameter listing tool.

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?

The tool has zero parameters, so parameter semantics are not a meaningful burden. The description appropriately focuses on return content and behavior instead of parameter documentation.

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

Purpose4/5

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

The description clearly states that it lists account notifications such as proposals, messages, and project updates, and returns unread counts. It is specific about the resource and returned content, though it does not explicitly differentiate itself from sibling list/search tools beyond the notification context.

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

Usage Guidelines3/5

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

Usage is implied: use this to see the latest notifications under the bell and their unread counts. It does not explicitly say when to choose this over siblings such as list_workstreams or when not to use it.

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

list_saved_searchesList saved searchesA
Read-onlyIdempotent
Inspect

This account's saved project searches with their filters and email alert setting.

Returns the project searches the signed-in account saved on the Jobs page: title, email alert (Never, Daily or Instantly) and filters. filters.query and filters.category can go straight into search_projects. PeoplePerHour allows 10 saved searches per account.

NameRequiredDescriptionDefault
cursorNonext_cursor from the previous call.

TDQS

A4/5.0
Behavior4/5

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

Annotations already cover read-only, idempotent and non-destructive behavior, so the description correctly spends its space elsewhere: it discloses the 10-saved-searches-per-account quota and enumerates the email alert values (Never, Daily, Instantly). It omits that results may be paginated despite exposing a cursor, which is the one meaningful behavioral gap.

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?

Two tight sentences, front-loaded with the resource and scope, followed by the returned fields and the quota constraint. No filler or repetition of the title.

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

Completeness4/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 carries the return-shape burden and does so by naming the fields and the alert enum values. The only shortfall is that pagination behavior (whether a cursor is always returned, page size) is left implicit.

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?

Only one parameter (cursor) with 100% schema description coverage, so the schema already defines it as the next_cursor from the previous call. The description adds nothing about the parameter, which is acceptable at this coverage level but earns no bonus.

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?

The description names a specific resource (saved project searches for the signed-in account) and states exactly what is returned: title, email alert, and filters. It distinguishes the tool from search_projects by noting the filters are inputs to that sibling rather than outputs of it.

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

Usage Guidelines3/5

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

Usage is implied — retrieve what the account has saved, then feed filters.query/filters.category into search_projects — but there is no explicit when-to-use versus save_search or search_projects, and no stated conditions or exclusions. The cross-reference to search_projects is the only routing signal.

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

list_watchlistList watchlistA
Read-onlyIdempotent
Inspect

Open projects on this account's watchlist (Favourite Jobs), with budget and proposal count.

Returns the open projects the signed-in account watches, in the same shape as search_projects. A watched project that has closed drops off the list. Pass next_cursor back as cursor with the same limit; it is null on the last page.

NameRequiredDescriptionDefault
limitNo1 to 50. Default: 20. Keep it the same across pages.
cursorNonext_cursor from the previous call.

TDQS

A4.1/5.0
Behavior4/5

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

Annotations already declare readOnly, idempotent, non-destructive, so the safety profile is covered. The description goes beyond them with genuinely useful behaviour: only open projects are returned, closed watched projects silently drop off, and the result set changes over time — all things an agent cannot read off the annotations or schema.

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?

Four short sentences, front-loaded with the resource and payload before the pagination detail. There is minor redundancy between the first two sentences (both restate that these are the watched open projects), but nothing is padded or off-topic.

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

Completeness4/5

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

For a two-param read tool with full schema coverage and no output schema, this is close to complete: population, return shape (by reference to search_projects), drop-off behaviour and pagination are all covered. Only an explicit routing statement against search_projects/list_my_projects is missing.

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. The description adds value beyond it by explaining the cursor/limit contract as a unit — reuse the same limit and feed next_cursor back as cursor — and by stating cursor is null on the last page, which tells the agent how pagination terminates.

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?

Specific verb plus a tightly scoped resource: 'open projects on this account's watchlist (Favourite Jobs)', with the returned fields named (budget, proposal count). It also distinguishes itself from the sibling that could be confused with it by noting the payload matches search_projects while the population is the watchlist, not a query.

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

Usage Guidelines3/5

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

Usage is implied rather than stated: an agent can infer this is the listing counterpart to watch_project/unwatch_project, but the description never says 'use this when you want the current watchlist' or excludes anything in favour of search_projects or list_my_projects. No prerequisites or when-not conditions are given.

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

list_workstreamsList WorkStreamsA
Read-onlyIdempotent
Inspect

This account's WorkStreams (conversations with hired freelancers) with the last message.

Returns the WorkStreams of the signed-in account, the conversation PeoplePerHour opens for each hire: title, link, unread message count and the last message with its time. It reads, never sends: replying is done on PeoplePerHour. Pass next_cursor back as cursor; it is null on the last page.

NameRequiredDescriptionDefault
cursorNonext_cursor from the previous call.

TDQS

A4.4/5.0
Behavior4/5

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

Annotations already declare readOnly/idempotent/non-destructive, but the description adds real context beyond them: the returned fields, the fact that replies must happen on PeoplePerHour, and the pagination termination signal (cursor null on the last page). No rate limits or auth details, so a 4 rather than 5.

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?

Front-loaded with the resource and scope, then behavior, then pagination; three short sentences with no filler. There is mild redundancy between the title line and the second sentence re-describing WorkStreams, which keeps it from 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?

There is no output schema, and the description compensates by enumerating what comes back (title, link, unread count, last message with time). Combined with scope, read-only guarantee, and pagination handling, an agent has everything needed to call 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?

Only one parameter with 100% schema coverage, so the baseline is 3. The description earns an extra point by explaining the round-trip usage ("Pass next_cursor back as cursor") and that the cursor is null on the last page — semantics the schema alone doesn't convey.

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 and resource (WorkStreams) plus scope: "This account's". The parenthetical "conversations with hired freelancers" defines the resource well enough that an agent can tell it apart from list_notifications, list_my_projects, or search_offers without opening another schema.

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?

Explicitly frames the read-only boundary ("It reads, never sends: replying is done on PeoplePerHour") and gives pagination instructions. It does not name a sibling alternative or a when-not condition, which keeps it short of a 5.

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

search_freelancersSearch freelancersA
Read-onlyIdempotent
Inspect

Freelancers by skill or keyword, with rate, rating, reviews, completed projects and skills.

Returns freelancers from the same search as Hire freelancers on PeoplePerHour: short name, profile URL, job title, location, hourly rate in the freelancer's currency, CERT level, rating in percent, review and project counts, skills and the start of their About text. hourly_rate filters in your account currency. get_freelancer returns the full profile. Pass next_cursor back as cursor with the same limit; it is null on the last page.

NameRequiredDescriptionDefault
sortNoOrder. Default: most-relevant.
limitNo1 to 50. Default: 20. Keep it the same across pages.
queryNoSkill or keywords, e.g. logo design.
cursorNonext_cursor from the previous call.
min_ratingNoOnly freelancers rated at least this percent.
hourly_rateNoHourly rate band in your account currency: *-10, 10-30, 30-50 or 50-*.
top_certifiedNoOnly freelancers with a CERT level.

TDQS

A4/5.0
Behavior4/5

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

Annotations already declare readOnly, openWorld, idempotent and non-destructive, so safety is covered; the description adds genuinely new behavior: the exact payload fields returned, currency semantics for hourly_rate, and a precise cursor-termination contract. Missing are result-cap/pagination limits beyond the cursor rule and any rate-limit or auth expectations.

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?

Two paragraphs, front-loaded with the resource and filters, followed by return-shape and pagination guidance. The return-field enumeration is a long run-on list that could be trimmed, but every element carries information an agent would otherwise have to guess.

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

Completeness4/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 takes on the burden of describing return values and does so in detail (fields, currency, About snippet), plus pagination and the hand-off to get_freelancer. It stops short of describing ordering defaults or result-total behavior, leaving mild gaps for a 7-parameter search tool.

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; the description earns above that by documenting the cross-parameter contract ('pass next_cursor back as cursor with the same limit') and clarifying that hourly_rate is evaluated in the account's currency. The rest (sort, min_rating, top_certified) is not elaborated beyond the schema.

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

Purpose4/5

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

The description states the resource (freelancers), the primary filter axes (skill or keyword, rate, rating, reviews, projects), and maps itself to a known external search ('same search as Hire freelancers on PeoplePerHour'). The verb is only implied by the name/title rather than written in the description, but the scope is unambiguous enough to separate it from search_projects and search_offers.

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?

It explicitly routes the agent to the sibling for deeper detail ('get_freelancer returns the full profile') and gives a concrete pagination procedure ('Pass next_cursor back as cursor with the same limit; it is null on the last page'). It does not state when to prefer this over search_projects/search_offers or any preconditions, so it falls short of the 5 bar.

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

search_offersSearch OffersA
Read-onlyIdempotent
Inspect

Fixed-price Offers freelancers sell, by keyword or price, with sales, rating and seller.

Returns Offers (fixed-price services, once called Hourlies) from the same search as the Offers page on PeoplePerHour: title, price in your account currency, delivery days, sales, rating in percent, category, tags and the freelancer who sells it. get_offer returns the description, add-ons and images. Pass next_cursor back as cursor with the same limit; it is null on the last page.

NameRequiredDescriptionDefault
sortNoOrder. Default: featured.
limitNo1 to 50. Default: 20. Keep it the same across pages.
queryNoKeywords, e.g. logo design.
cursorNonext_cursor from the previous call.
price_rangeNoPrice band in your account currency: 0-19, 20-50, 50-100 or 100-*.

TDQS

A4.4/5.0
Behavior4/5

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

Annotations already declare readOnly/idempotent/non-destructive, so the safety bar is low; the description adds real value beyond that by enumerating the returned fields and disclosing the termination signal ('it is null on the last page') plus the stable-limit paging rule. It omits auth or rate-limit context, which keeps it from a 5.

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?

Purpose is front-loaded in the first sentence, then return fields, then the sibling pointer, then pagination — a clean priority order with no filler. Even the historical note ('once called Hourlies') earns its place by mapping older terminology to the resource.

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

Completeness4/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 carries the return-value burden and does it: it lists the fields returned and explains how to know when paging ends. Minor gaps remain (no mention of total result counts or ordering of the returned list beyond the sort param), but nothing needed 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.

Parameters4/5

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

Schema coverage is 100%, so baseline is 3, but the description adds meaning beyond it — price is denominated in your account currency (relevant to interpreting price_range and the returned price), and the cursor/limit pairing is framed as a paging contract rather than two independent fields. Slight overlap with the schema's own 'keep it the same across pages' note keeps it at 4.

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 and resource ('fixed-price Offers freelancers sell, by keyword or price') and immediately scopes what it returns: sales, rating, seller. It also names the sibling it is not — get_offer returns description, add-ons and images — so an agent can distinguish the list-search from the detail-fetch without opening either schema.

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?

Explicitly routes the agent: use this for searching, use get_offer for description/add-ons/images, and gives the pagination protocol (pass next_cursor back as cursor with the same limit; null on the last page). It does not contrast against the other search siblings (search_projects, search_freelancers), but the fixed-price framing makes the boundary inferable.

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

search_projectsSearch projectsA
Read-onlyIdempotent
Inspect

Open projects buyers posted, newest first, with budget, category, proposals and the brief's start.

Returns open projects from the same search as the Jobs page on PeoplePerHour, newest first. Filter by keyword, top category, or posting time: with since, only projects posted after it come back, so an agent polling for new work reads only what arrived since its last check. Times are UTC. budget.type is fixed_price or hourly (then the amount is per hour), in the buyer's currency. freelancer_country is set when only freelancers from that country may send a proposal. get_project returns the full brief. Pass next_cursor back as cursor for the next page; it is null when nothing more matches. With since, one call scans at most 200 of the newest projects, so a page can hold fewer than limit and still have a next_cursor.

NameRequiredDescriptionDefault
limitNo1 to 50. Default: 20.
queryNoKeywords to search for.
sinceNoOnly projects posted after this time (ISO 8601; without a zone it is UTC).
cursorNonext_cursor from the previous call.
categoryNoOnly projects in this top category.

TDQS

A4.6/5.0
Behavior5/5

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

Annotations already cover read-only, open-world and idempotent, yet the description still adds substantial behavior: results are newest-first, 'times are UTC', next_cursor is null when exhausted, no matches exist, and one call scans at most 200 newest projects with 'since', which explains the key trap (a short page that still has a next_cursor).

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?

Front-loaded with what it returns and its ordering, then filters, then pagination — a sensible order. It loses a point for redundancy: 'newest first' appears in both the first and second sentences, and the opening two sentences retread the same ground.

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 carries the return-value burden and does it: budget type and currency, category, proposal count and brief start, plus a full pagination contract. Nothing an agent needs in order to page or poll correctly is missing.

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 baseline is 3, but the description genuinely extends it: 'cursor' is tied to next_cursor from the previous call, 'since' is framed as the polling watermark, and 'limit' is qualified by the scan cap. Some of the field talk (budget.type, freelancer_country) describes return values rather than parameters, which reads as slightly off-register but is not misleading given there is no output schema.

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?

Names a specific verb and resource ('open projects buyers posted', 'newest first') and immediately scopes it against the Jobs page search. The description of returned fields plus the explicit handoff to get_project for the full brief lets an agent distinguish it from search_freelancers and search_offers without opening a schema.

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?

Gives concrete usage context: poll with 'since' to read only new postings, and use get_project when the full brief is needed. It doesn't explicitly rule out search_offers or search_freelancers, but the resource distinction is clear enough that no agent would confuse them.

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

unwatch_projectUnwatch projectA
Destructive
Inspect

Take a project off this account's watchlist.

Removes the project from the watchlist of the signed-in account. Nobody else is told.

NameRequiredDescriptionDefault
project_idYesproject_id from list_watchlist, or the project's URL.

TDQS

A3.6/5.0
Behavior3/5

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

Annotations already declare destructiveHint=true, openWorldHint=true and idempotentHint=false, so safety framing is covered. The description adds one genuinely useful behavioral fact — no notifications are sent to others ('Nobody else is told'). It does not say what happens if the project is not on the watchlist (error vs no-op), which matters given idempotentHint=false.

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?

Two short sentences, front-loaded with the action and followed by the one piece of behavioral context an agent can't get from structured fields. No padding.

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

Completeness4/5

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

For a single-parameter, non-idempotent mutation with no output schema, the definition covers what is removed and who is affected. The only real gap is failure behavior when the project is not currently watched.

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 coverage is 100% and the schema already explains that project_id comes from list_watchlist or the project URL. The description adds nothing further about the parameter, so the baseline of 3 applies.

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

Purpose4/5

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

States a specific verb+resource ('Take a project off this account's watchlist') and immediately narrows scope to the signed-in account's watchlist. The counterpart sibling watch_project is obvious from the verb pairing, though it is never named explicitly.

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

Usage Guidelines3/5

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

Usage is implied by the account-scoped phrasing, and the pointer in the schema to list_watchlist gives a source for the ID. However, there is no explicit 'use this instead of X' guidance and no stated precondition (e.g., project must currently be watched).

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

watch_projectWatch projectA
Idempotent
Inspect

Add a project to this account's watchlist (Favourite Jobs) to come back to it later.

Adds the project to the watchlist of the signed-in account, the heart on the project page. The buyer is not notified. Watching a project already on the list changes nothing. list_watchlist reads the list and unwatch_project takes it off.

NameRequiredDescriptionDefault
project_idYesproject_id from search_projects, or the project's URL.

TDQS

A4.2/5.0
Behavior4/5

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

Adds context beyond annotations: buyer is not notified, already-watched calls are no-ops (reinforcing idempotentHint with concrete semantics), and the account-scoped nature of the adding. Missing auth requirements or failure modes, but the annotation set is already rich.

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 tight sentences, front-loaded with the action and purpose, followed by behavior and then navigation pointers. No filler.

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

Completeness4/5

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

One-param mutation tool with full annotations but no output schema; the description covers purpose, notification side effect, idempotence semantics, and sibling routing. Only return-value/error behavior is unaddressed, which is minor here.

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 coverage is 100% and the single parameter is documented with a useful note about sourcing it from search_projects or the URL. The description itself adds nothing param-specific, so 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?

Specific verb+resource ('Add a project to this account's watchlist'), plus a concrete user-facing alias (Favourite Jobs / 'the heart on the project page'). Clearly distinguished from siblings list_watchlist and unwatch_project by name.

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?

Explicitly states what happens when already watched ('changes nothing') and names the read/remove siblings for alternative intent. No explicit prerequisites or exclusions beyond that, but the when-to-use is clear.

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. 17 tool updatesv0.1.0
    • First observeddelete_saved_search
    • First observedget_account
    • First observedget_freelancer
    • First observedget_offer
    • First observedget_project
    • First observedlist_categories
    • First observedlist_my_projects
    • First observedlist_notifications
    • First observedlist_saved_searches
    • First observedlist_watchlist
    • First observedlist_workstreams
    • First observedsave_search
    • First observedsearch_freelancers
    • First observedsearch_offers
    • First observedsearch_projects
    • First observedunwatch_project
    • First observedwatch_project

TDQS

A3.9/5.0

Scored across 17 tools

Disambiguation5/5

Each tool targets a distinct resource and action: search_* for discovery, get_* for single-resource detail, list_* for account-scoped collections, and paired watch/unwatch and save/delete_saved_search verbs. The only near-pair, list_watchlist vs search_projects, is clearly differentiated by scope and the description notes they share a shape without being confusable.

Naming Consistency5/5

Every tool follows consistent snake_case verb_noun form (get_project, search_offers, list_saved_searches, delete_saved_search). Opposing operations use symmetric prefixes (watch_project/unwatch_project) and related verbs (search vs get vs list) are used meaningfully throughout.

Tool Count4/5

17 tools is slightly above the ideal 3–15 range but each maps to a real, non-redundant operation across several domains (projects, offers, freelancers, account, watchlist, saved searches, notifications, WorkStreams). Nothing feels padded, though the surface is on the heavy side.

Completeness3/5

Discovery and read coverage is thorough (search/get for projects, offers, freelancers; account, watchlist, saved searches, notifications, WorkStreams), but the surface is essentially read-only with notable gaps: no proposal submission, no message replies, no project creation for buyers, and no marking notifications read. Some of these are explicitly out of scope by design, which limits agent end-to-end workflows.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers