← Upwork MCP

MCP tool reference

24 tools. Everything a signed-in user can do in the app, except billing and account deletion. Machine-readable copy at /upwork-mcp/docs.md.

Connect

Server URL: https://tryvibeworker.com/api/mcp (streamable HTTP).

Claude, ChatGPT, other OAuth clients: add the URL as a custom connector, sign in to Vibeworker, allow. OAuth 2.1 with dynamic client registration, nothing to paste. Walkthrough on the setup page.

Claude Code, Cursor, Windsurf, scripts: Authorization: Bearer vw_… with a key from Settings → Developer.

Job IDs everywhere are the vw_… public IDs returned by list_jobs and search_jobs.

Limits

  • Subscribers: unlimited.
  • Free accounts: a one-time pool of 25 fresh jobs across list_jobs, search_jobs, get_job, and get_proposal_context, then up to 100 jobs a day that are older than 24 hours.
  • generate_proposal is subscribers only. Free accounts call get_proposal_context and let the assistant draft.
  • import_upwork_profile: 8 a day. Every other tool is uncounted on every plan, so setting an account up through an assistant costs nothing.

Jobs

list_jobsread

Get your ranked Upwork job feed from Vibeworker. Returns jobs scored and ranked by match to your profile. Use this to find the best opportunities to apply to.

limitnumberNumber of jobs to return (max 50)
sort"match" | "newest" | "budget" | "quick_win"Sort order: match (best fit), newest, budget (highest pay), quick_win (fast completable)
jobType"Fixed" | "Hourly"Filter to Fixed or Hourly jobs only
minBudgetnumberMinimum budget in USD
minScorenumberMinimum match score 0-1 (e.g. 0.7 = top 30%)
categoriesstring[]Filter to specific Upwork categories
search_jobsread

Search your Upwork job database by keyword. Searches job titles and descriptions from the last 48 hours.

querystring · requiredSearch query — keywords, skills, or job type
limitnumberNumber of results to return
get_jobread

Get full details for a specific Upwork job including description, client info, all scores, and direct Upwork URL. Use before drafting a proposal.

idstring · requiredJob ID from list_jobs
update_job_statuswrite

Record what happened with a job. Stages (saved, applied, interviewing, won, lost) are stamped with the current time on the job's Activity row; pass undo:true to clear one. skipped hides the job from the feed. rejected logs that you passed on it. Notes are appended to the Activity row. Every stage that changes the dashboard card changes it here too.

jobIdstring · requiredJob ID from list_jobs, search_jobs, get_job, or list_activity
action"saved" | "applied" | "interviewing" | "won" | "lost" | "skipped" | "rejected" · required
undobooleanClear this stage instead of setting it (e.g. applied by mistake)
notesstringAnything worth remembering about this job: who you spoke to, what they asked, when to follow up. Appended to the row's notes.
list_activityread

The freelancer's Activity tab: every job they saved, drafted a proposal for, applied to, or recorded an outcome on, newest activity first, with the date each stage was reached and their notes. Rows outlive the job feed, so this is the place to answer "what happened with the jobs I applied to". Use update_job_status to move a job along; get_proposal to read a draft.

daysintegerOnly rows with activity in the last N days (default 30). Omit and pass all:true for everything.
allbooleanReturn all rows regardless of age
view"all" | "saved" | "proposals" | "applied" | "outcomes"Filter to one stage group (default all)

Proposals

get_proposal_contextread

Get everything needed to draft a proposal for a specific job: full job details, the client's screening questions, the freelancer's persona (projects, past jobs with client quotes, rate), their style notes, and the writing rules to follow. Call this before drafting a proposal yourself; subscribers can call generate_proposal instead.

jobIdstring · requiredJob ID from list_jobs or get_job
generate_proposalwrite

Generate a proposal with Vibeworker's own writer: a cover letter, one answer per screening question, and which persona items it drew on. Uses the persona and style notes. Saved to the job so it appears in the dashboard. Subscribers only; free accounts should call get_proposal_context and draft it themselves.

jobIdstring · requiredJob ID from list_jobs, search_jobs, or get_job
save_proposalwrite

Save a proposal you wrote or edited for a job, so it sits on the job's Activity row next to the freelancer's notes and stages. Call get_proposal_context first for the job, screening questions, persona and writing rules. Calling again for the same job replaces the draft, so this is also how you revise one (including one from generate_proposal). Free on every plan. Does not submit anything to Upwork.

jobIdstring · requiredJob ID from list_jobs, search_jobs, get_job, or list_activity
coverLetterstring · requiredThe cover letter, plain text
answersobject[]One entry per screening question, in the order the job lists them
list_proposalsread

List proposals generated for this account, newest first, with the job each belongs to.

limitintegerDefault 10

Persona

get_personaread

Get the freelancer persona used to write proposals: name, title, rate, overview, skills, proof points, portfolio projects, past jobs with client quotes, employment, and the style notes proposals must follow. Separate from get_profile, which is the text the job feed is ranked against.

No parameters.

update_personawrite

Update the freelancer persona used for proposals. Pass only the fields to change. Scalar fields replace, list fields (skills, projects, workHistory, employment) replace the whole list when given, so read with get_persona first and send the full list back. proposalNotes are free-text style instructions every proposal follows.

namestring
titlestringHeadline, e.g. "Full-stack developer, automation and AI integrations"
locationstring
hourlyRatestringExactly as it should appear in a proposal, e.g. "$45/hr"
experienceYearsstringe.g. "8 years"
overviewstringThe Upwork bio text
skillsstring[]
proofPointsstringJob Success Score, badges, verifications, freeform
projectsobject[]
workHistoryobject[]
employmentobject[]
proposalNotesstringStyle instructions for every proposal, e.g. "Always mention I work US hours. Never offer a discount."
import_upwork_profilewrite

Parse the text of an Upwork profile page (select-all, copy) into the structured persona: name, title, rate, overview, skills, portfolio, work history with client feedback, employment. Saves it when the persona is empty; otherwise returns the parsed result for review unless overwrite is true. Limited to a few imports per day.

textstring · requiredThe full text of the Upwork profile page
overwritebooleanReplace an existing persona with the parsed result. Default false.

Profile

get_profileread

Get your Vibeworker freelancer profile — skills, niche, scoring mode, and subscribed categories. Useful context before evaluating jobs.

No parameters.

update_profilewrite

Update the freelancer profile Vibeworker uses to score and rank jobs, and/or the scoring mode. Updating profileText re-embeds your profile and re-matches your recent job history, so this can take a few seconds.

profileTextstringFree-text description of your skills, niche, rate, and preferences — this is what scoring is matched against
scoringMode"digest" | "reviewStacking" | "sniper" | "highValue"digest = balanced default, reviewStacking = optimize for winnable quick jobs, sniper/highValue = optimize for high-value matches

Filters

list_filtersread

List all of your filter presets, including which one is active for the dashboard and which for notifications.

No parameters.

create_filterwrite

Create a new filter preset (a saved set of job-matching rules — budget, keywords, categories, etc). This is how you set up Vibeworker's feed and notifications for a user from scratch.

namestring · requiredDisplay name for this filter, e.g. "High-value React work"
categoriesstring[]Upwork categories to match against. Omit or empty = all categories.
platformsstring[]Non-Upwork platforms to include (Upwork is always included). Omit = Upwork-only.
jobType"Fixed" | "Hourly"Restrict to Fixed or Hourly jobs
experienceLevel"Entry Level" | "Intermediate" | "Expert"Restrict to a client-stated experience level
budgetMinnumberMinimum budget in USD (applies regardless of job type)
budgetMinHourlynumberMinimum budget in USD, hourly jobs only
budgetMinFixednumberMinimum budget in USD, fixed-price jobs only
hideUnpostedBudgetbooleanHide jobs with no budget stated
connectsMaxnumberMaximum Upwork connects required to apply
requirePaymentVerifiedbooleanOnly show jobs from payment-verified clients
minClientRatingnumberMinimum client star rating (0-5)
minClientSpentnumberMinimum client lifetime spend in USD
minHireRatenumberMinimum client hire rate, 0-1
minHiresnumberMinimum total freelancers the client has hired
keywordsIncludestring[]At least one of these keywords must appear in title/description
keywordsRequirestring[]All of these keywords must appear in title/description
keywordsExcludestring[]Jobs containing any of these keywords are excluded
excludeLocationsstring[]Exclude jobs whose client location contains any of these strings
postedWithinHoursnumberOnly show jobs posted within this many hours
update_filterwrite

Update an existing filter preset. Only the fields you pass are changed — everything else on the filter is left as-is.

idstring · requiredFilter preset id (from list_filters)
namestringNew display name
categoriesstring[]Replace the categories this filter matches. Omit to leave unchanged.
platformsstring[]Replace the non-Upwork platforms included. Omit to leave unchanged.
jobType"Fixed" | "Hourly"Restrict to Fixed or Hourly jobs
experienceLevel"Entry Level" | "Intermediate" | "Expert"Restrict to a client-stated experience level
budgetMinnumberMinimum budget in USD (applies regardless of job type)
budgetMinHourlynumberMinimum budget in USD, hourly jobs only
budgetMinFixednumberMinimum budget in USD, fixed-price jobs only
hideUnpostedBudgetbooleanHide jobs with no budget stated
connectsMaxnumberMaximum Upwork connects required to apply
requirePaymentVerifiedbooleanOnly show jobs from payment-verified clients
minClientRatingnumberMinimum client star rating (0-5)
minClientSpentnumberMinimum client lifetime spend in USD
minHireRatenumberMinimum client hire rate, 0-1
minHiresnumberMinimum total freelancers the client has hired
keywordsIncludestring[]At least one of these keywords must appear in title/description
keywordsRequirestring[]All of these keywords must appear in title/description
keywordsExcludestring[]Jobs containing any of these keywords are excluded
excludeLocationsstring[]Exclude jobs whose client location contains any of these strings
postedWithinHoursnumberOnly show jobs posted within this many hours
tune_filterwrite

Tighten or loosen a filter's client-quality bar until it lands near a target number of jobs per day, using the last 7 days of jobs in its categories. Same ratchet onboarding uses. Returns the resulting filters; pass apply: true to save them onto the filter.

filterIdstring · requiredFilter ID from list_filters
targetPerDayinteger · requiredJobs per day to aim for, e.g. 10
applybooleanSave the tuned filters onto the filter. Default false (preview only).
assign_filterwrite

Make a filter the active one for either the dashboard feed or notifications.

presetIdany · requiredFilter preset id, or null to unassign
surface"dashboard" | "notification" · requiredWhich surface to assign this filter to
reorder_filterswrite

Reorder your filter presets (affects dashboard tab order).

idsstring[] · requiredFilter preset ids in the desired order
delete_filterdestructive

Permanently delete a filter preset. This cannot be undone.

idstring · requiredFilter preset id to delete

Alerts and feeds

update_filter_notificationswrite

Configure which notification channels fire for a filter, and the score threshold that triggers them.

idstring · requiredFilter preset id
notifyChannelsobjectOnly the channel keys you include are changed — other channels already configured on this filter are left as-is. web_push = browser push, push = mobile app push, webhook = POST a signed payload to a URL (requires url when enabling), telegram = Telegram bot, email = email digest.
notifyThresholdnumberScore threshold that triggers a notification (meaning depends on scoring mode)
get_feed_urlwrite

Turn on the private RSS feed for a filter and return its URL, for feed readers, Zapier, Make, or n8n. Returns the existing URL if the feed is already on. Subscribers only.

filterIdstring · requiredFilter ID from list_filters

Notes for assistants

  • Nothing here submits to Upwork. The user always applies themselves; get_job and generate_proposal return the Upwork URL to open.
  • delete_filter is irreversible. Confirm with the user first.
  • Read with get_persona before update_persona: list fields replace the whole list.