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.
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.
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.list_jobsreadGet 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 onlyminBudgetnumberMinimum budget in USDminScorenumberMinimum match score 0-1 (e.g. 0.7 = top 30%)categoriesstring[]Filter to specific Upwork categoriessearch_jobsreadSearch your Upwork job database by keyword. Searches job titles and descriptions from the last 48 hours.
querystring · requiredSearch query — keywords, skills, or job typelimitnumberNumber of results to returnget_jobreadGet 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_jobsupdate_job_statuswriteRecord 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_activityaction"saved" | "applied" | "interviewing" | "won" | "lost" | "skipped" | "rejected" · requiredundobooleanClear 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_activityreadThe 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 ageview"all" | "saved" | "proposals" | "applied" | "outcomes"Filter to one stage group (default all)get_proposal_contextreadGet 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_jobgenerate_proposalwriteGenerate 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_jobsave_proposalwriteSave 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_activitycoverLetterstring · requiredThe cover letter, plain textanswersobject[]One entry per screening question, in the order the job lists themlist_proposalsreadList proposals generated for this account, newest first, with the job each belongs to.
limitintegerDefault 10get_personareadGet 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_personawriteUpdate 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.
namestringtitlestringHeadline, e.g. "Full-stack developer, automation and AI integrations"locationstringhourlyRatestringExactly as it should appear in a proposal, e.g. "$45/hr"experienceYearsstringe.g. "8 years"overviewstringThe Upwork bio textskillsstring[]proofPointsstringJob Success Score, badges, verifications, freeformprojectsobject[]workHistoryobject[]employmentobject[]proposalNotesstringStyle instructions for every proposal, e.g. "Always mention I work US hours. Never offer a discount."import_upwork_profilewriteParse 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 pageoverwritebooleanReplace an existing persona with the parsed result. Default false.get_profilereadGet your Vibeworker freelancer profile — skills, niche, scoring mode, and subscribed categories. Useful context before evaluating jobs.
No parameters.
update_profilewriteUpdate 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 againstscoringMode"digest" | "reviewStacking" | "sniper" | "highValue"digest = balanced default, reviewStacking = optimize for winnable quick jobs, sniper/highValue = optimize for high-value matcheslist_filtersreadList all of your filter presets, including which one is active for the dashboard and which for notifications.
No parameters.
create_filterwriteCreate 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 jobsexperienceLevel"Entry Level" | "Intermediate" | "Expert"Restrict to a client-stated experience levelbudgetMinnumberMinimum budget in USD (applies regardless of job type)budgetMinHourlynumberMinimum budget in USD, hourly jobs onlybudgetMinFixednumberMinimum budget in USD, fixed-price jobs onlyhideUnpostedBudgetbooleanHide jobs with no budget statedconnectsMaxnumberMaximum Upwork connects required to applyrequirePaymentVerifiedbooleanOnly show jobs from payment-verified clientsminClientRatingnumberMinimum client star rating (0-5)minClientSpentnumberMinimum client lifetime spend in USDminHireRatenumberMinimum client hire rate, 0-1minHiresnumberMinimum total freelancers the client has hiredkeywordsIncludestring[]At least one of these keywords must appear in title/descriptionkeywordsRequirestring[]All of these keywords must appear in title/descriptionkeywordsExcludestring[]Jobs containing any of these keywords are excludedexcludeLocationsstring[]Exclude jobs whose client location contains any of these stringspostedWithinHoursnumberOnly show jobs posted within this many hoursupdate_filterwriteUpdate 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 namecategoriesstring[]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 jobsexperienceLevel"Entry Level" | "Intermediate" | "Expert"Restrict to a client-stated experience levelbudgetMinnumberMinimum budget in USD (applies regardless of job type)budgetMinHourlynumberMinimum budget in USD, hourly jobs onlybudgetMinFixednumberMinimum budget in USD, fixed-price jobs onlyhideUnpostedBudgetbooleanHide jobs with no budget statedconnectsMaxnumberMaximum Upwork connects required to applyrequirePaymentVerifiedbooleanOnly show jobs from payment-verified clientsminClientRatingnumberMinimum client star rating (0-5)minClientSpentnumberMinimum client lifetime spend in USDminHireRatenumberMinimum client hire rate, 0-1minHiresnumberMinimum total freelancers the client has hiredkeywordsIncludestring[]At least one of these keywords must appear in title/descriptionkeywordsRequirestring[]All of these keywords must appear in title/descriptionkeywordsExcludestring[]Jobs containing any of these keywords are excludedexcludeLocationsstring[]Exclude jobs whose client location contains any of these stringspostedWithinHoursnumberOnly show jobs posted within this many hourstune_filterwriteTighten 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_filterstargetPerDayinteger · requiredJobs per day to aim for, e.g. 10applybooleanSave the tuned filters onto the filter. Default false (preview only).assign_filterwriteMake a filter the active one for either the dashboard feed or notifications.
presetIdany · requiredFilter preset id, or null to unassignsurface"dashboard" | "notification" · requiredWhich surface to assign this filter toreorder_filterswriteReorder your filter presets (affects dashboard tab order).
idsstring[] · requiredFilter preset ids in the desired orderdelete_filterdestructivePermanently delete a filter preset. This cannot be undone.
idstring · requiredFilter preset id to deleteupdate_filter_notificationswriteConfigure which notification channels fire for a filter, and the score threshold that triggers them.
idstring · requiredFilter preset idnotifyChannelsobjectOnly 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_telegram_linkwriteConnect Telegram for job alerts. Returns a one-time link the freelancer opens in Telegram to link their account; it expires in 15 minutes. After linking, turn Telegram on for a filter with update_filter_notifications.
No parameters.
get_feed_urlwriteTurn 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_filtersget_job and generate_proposal return the Upwork URL to open.delete_filter is irreversible. Confirm with the user first.get_persona before update_persona: list fields replace the whole list.