upwork-mcp
upwork-mcp
An MCP server for Upwork automation. Search jobs, draft and submit proposals, manage messages and contracts — all from Claude Desktop or any MCP-compatible client.
Features
Job Search — keyword search with filters (budget, hourly rate, experience level, client rating, recency), automatic scoring and red-flag detection
Proposal Workflow — draft from templates, preview, then submit with explicit confirmation; daily limit enforced
Client Vetting — 7-condition red-flag checker (payment verification, rating, hire history, account age, repost count, proposal volume, hourly rate floor)
Messages — list unread conversations, read threads, draft and send replies
Contracts — list active/past contracts, view details and work diary entries
Session Safety — persistent Chromium profile, Cloudflare detection, 7-day idle expiry, domain restriction to
upwork.comAudit Log — every tool call appended to
~/.upwork-mcp/audit.log(metadata only, no content)
Requirements
Python 3.11+
uv (recommended) or pip
A valid Upwork account
Installation
Using uv (recommended)
git clone https://github.com/kubegrind/upwork-mcp
cd upwork-mcp
uv sync
uv run playwright install chromiumUsing pip
git clone https://github.com/kubegrind/upwork-mcp
cd upwork-mcp
pip install -e .
playwright install chromiumConfiguration
Claude Desktop
Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"upwork": {
"command": "uv",
"args": [
"--directory",
"/absolute/path/to/upwork-mcp",
"run",
"upwork-mcp"
]
}
}
}Claude Code
claude mcp add upwork -- uv --directory /absolute/path/to/upwork-mcp run upwork-mcpEnvironment Variables
Variable | Default | Description |
|
| Data directory for profile, logs, templates |
|
| Minimum acceptable hourly rate for red-flag detection |
Authentication
The server uses a persistent Chromium browser profile. On first run, authenticate manually:
uv run upwork-mcp --no-headlessA browser window will open. Log in to Upwork normally. The session is saved to ~/.upwork-mcp/profile/ and reused on subsequent runs. Sessions expire after 7 days of inactivity.
Tools
Jobs
Tool | Description |
| Search by keyword with filters; returns scored, ranked results |
| Full job details including client history and interview rate |
| Score a specific job 1–10 |
| Check a client against 7 red-flag conditions |
| Run a saved search from |
Proposals
Tool | Description |
| List submitted proposals with status |
| Details for a specific proposal |
| Draft a proposal from a template |
| Preview a draft before submission |
| WRITE — submit a proposal (requires |
| WRITE — withdraw a submitted proposal (requires |
Messages
Tool | Description |
| List unread conversations |
| Read the last 10 messages in a thread |
| Draft a reply for review |
| WRITE — send a message (requires |
Contracts
Tool | Description |
| List active and past contracts |
| Contract details and milestones |
| Hours and memo entries for a contract |
Profile
Tool | Description |
| Name and title from your profile |
| Current connects balance with low-balance warning |
| JSS, Top Rated status, and total earnings |
Session & Audit
Tool | Description |
| Verify the session is authenticated |
| WRITE — close the browser session |
| WRITE — restart the browser context |
| View the last N audit log entries |
Proposal Templates
Templates live in ~/.upwork-mcp/templates/. The default template is loaded from default.txt if it exists. Pass a filename via template_name to use a custom template.
Supported variables:
{job_title} {client_name} {key_skill}
{estimated_timeline} {rate} {years_experience}
{industries} {custom_paragraph} {start_date}
{your_name}Example template (~/.upwork-mcp/templates/default.txt):
Hi {client_name},
I noticed you're looking for {key_skill} help on {job_title}.
I have {years_experience} years of relevant experience and can deliver {estimated_timeline}.
My rate is {rate}.
{your_name}Saved Searches
Create JSON files in ~/.upwork-mcp/searches/ to save search configurations:
{
"query": "devops kubernetes",
"experience_level": "expert",
"budget_min": 500,
"client_rating_min": 4.5
}Run with upwork_run_saved_search(search_name="devops").
Job Scoring
Jobs are scored 1–10 using a weighted model:
Factor | Weight |
Budget match | 30% |
Skill match | 25% |
Client quality | 20% |
Proposal competition | 15% |
Recency | 10% |
Jobs scoring below 4.0 are filtered from results. Jobs scoring 7.0 or above are marked [HIGH PRIORITY].
Safety
WRITE tools (
submit_proposal,withdraw_proposal,send_message,close_session,rotate_session) requireconfirmed: true— the model cannot act without explicit user confirmationDaily proposal limit — hard block at 10 submissions per day
Domain restriction — browser navigation is restricted to
upwork.comNo credential exposure — cookies and tokens are never returned, logged, or printed
Path traversal protection — template and saved search filenames are validated with
Path.is_relative_to()Audit log — all tool calls recorded with timestamp, action type, target, and status
Development
uv sync --extra dev
uv run pytest
uv run ruff check src
uv run mypy srcLicense
MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/kubegrind/upwork-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server