WorkforceGPT for agents

An MCP server that lets any compatible agent score a job description and build a structured role profile (responsibilities, skills with proficiency levels, and qualifications) on behalf of someone with a WorkforceGPT account. Connect it in one step, no API key.

Server URL https://workforcegpt.ai/mcp
Part 1

Quick start

Four steps, and the first three involve no code at all. By the end of step two you will have scored a real job description by asking for it in plain English. Step four is for when you want that to happen the same way every time.

You need two things: a WorkforceGPT account, which is free to create and needs a verified email address, and a copy of Claude (or any other MCP client).

1

Connect Claude to the server

Everything on this page hangs off the URL in the box above. There is no API key to paste and no client id to request in advance, because your client registers itself the first time it connects.

Claude web, desktop or Cowork

Open Settings, go to Connectors, and choose Add custom connector. Name it whatever you like, paste the server URL, and add it.

That menu belongs to Anthropic and may move. Their guide to custom connectors is the version that stays current, including which plans it is available on.

Claude Code

Add it once, then sign in:

claude mcp add --transport http workforcegpt https://workforcegpt.ai/mcp

Run /mcp inside Claude Code to complete the sign-in, and claude mcp list to confirm it says connected.

Any other MCP client

Give it the URL and nothing else. The server publishes the standard discovery documents, so a client that speaks OAuth finds the rest by itself. The detail is in how the connection works.

Whichever route you take, a browser window opens and asks you to sign in to WorkforceGPT and approve the connection. The screen names the application asking, the web address the approval will be sent to, and exactly what it is asking to do. Read that middle one: it is the one thing an application cannot fake about itself.

From then on the agent acts as you, against your account and your allowance. You can disconnect it whenever you like from your settings page, and that takes effect at once.

2

Ask for something

There is no syntax to learn. Claude reads the tool descriptions and picks one. Try any of these:

"Here is a job description we are about to post. Score it and tell me what to fix." (then paste it in) Calls assess_job_description and answers on the spot, with a score, what the score means, and what to do about it.

"Build a role profile for a Senior Data Analyst at Northwind." Calls generate_role, which starts the work and hands back an id, then checks back on it until it is done. See how generation behaves.

"What have I got left on my WorkforceGPT account?" Calls get_account_status. Worth asking before you plan a batch of work rather than after.

If something is refused, the answer says which limit you hit and what the account has left, in words, rather than making the agent guess from a status code.

3

Add the two ready-made Skills

A Skill is a Markdown file of instructions that Claude loads when a conversation calls for it. We ship two. They add no capability: everything they do, you just did without them in step two.

What they add is judgment, i.e. the parts a tool description has no room for. When is a tool worth calling at all? How do you spend a small allowance well? How do you turn a company's internal job title into one the labor market will recognize? And what does importance_to_role: 1 mean? It means High, which is the opposite of how it reads.

assess-job-description
Scoring an existing job description, and deciding what to do about the score.
build-role-profile
Generating a role profile, and getting the title right so the labor-market match succeeds.

In Claude Code

Each skill is one SKILL.md in a folder named after it:

SRC=https://workforcegpt.ai/mcp/skills
DEST=~/.claude/skills

for s in assess-job-description build-role-profile; do
  mkdir -p $DEST/$s && curl -s $SRC/$s.md -o $DEST/$s/SKILL.md
done

Use .claude/skills/ inside a project instead if you want it to travel with the repository rather than follow you around.

In the Claude apps

Download each file from the links above, put it in a folder named after the skill as SKILL.md, zip that folder, and upload it in Claude's settings. Anthropic's Agent Skills guide has the current path and which plans it needs.

Nothing else needs them. An agent that is not Claude reads the same guidance from each tool's description and inputSchema, which is where the non-optional parts live.
4

Write a Skill of your own

You do not need to be a developer for this and you do not need to start from nothing. The two skills above already handle the hard general problems. What they cannot know is how your organization does this: your job families, your leveling, your house format, the approval step you want before anything is written down.

So the skill worth writing is a thin one that wraps ours. Here is a complete example. Save it as SKILL.md in a folder named northwind-role-profiles, in the same place you put the two above.

---
name: northwind-role-profiles
description: Create a role profile that follows Northwind's job architecture conventions. Use when someone asks for a job profile, role definition, competency model or skills framework for a Northwind position, or wants an existing job description turned into one.
---

# Northwind role profiles

Our job architecture has rules WorkforceGPT does not know about. Apply them
around the tools, not instead of them.

## Before spending anything

Call `get_account_status` and tell the person what the account has left. Do
not guess the allowance, it is configurable and this file will not be updated
when it changes.

## Getting the title right

We title roles internally like "Staff Engineer II, Payments Platform". That
will not match labor-market data and the generation will come back thin. Send
the occupation instead, i.e. "Software Engineer", and keep our internal title
for the heading you write at the end.

If the person insists on the internal title, pass the old job description as
`job_description` and set `use_job_description_if_title_not_found` to true, so
there is something to build from when the title does not match.

## Generating

Call `generate_role` with `role_title` and `company_name`. It returns a
`role_id` rather than a profile. Poll `check_role_status` with that id until
`status` is no longer `pending`.

## Reading the result

`importance_to_role` is 1 for High, 2 for Medium and 3 for Low. It reads like
the opposite of what it means, so print the label and never the number.

## What to hand back

A table of responsibility, skill and proficiency level, then ask whether to
add it to the job architecture sheet. Never add it without being asked.

The four things that decide whether it works

  1. The description is the trigger. Until Claude decides to open the file it can see only the name and the description, so write the description about the situations somebody will be in, not about what the file contains. "Use when someone asks for a job profile…" beats "Tools for role profiles."
  2. Name the tools exactly. generate_role, not "the generate tool". The names are in the tool list and they are what the agent has to type.
  3. Do not write the allowance into the file. It is configurable, and a file sitting on your laptop is not redeployed when it changes. Point at get_account_status instead, which is always right.
  4. Say what to do with the answer. A score with no interpretation attached is a score an agent will interpret generously. Tell it what good looks like and what to do about bad.

Checking that it loaded

Start a new conversation and say something that should trigger it, without naming the skill. If Claude does not reach for it, the description is the problem rather than the body: it has to sound like the thing the person actually asked for.

Part 2

Reference

The detail underneath the quick start: every tool and its arguments, what the scopes mean, how the limits work, and the protocol itself.

Tools

10 tools. The scope beside each one is what your client must have been granted to call it; a call without it comes back as a tool error naming the scope you need.

assess_job_description
assess

Score a job description from 0-100 on how cleanly it can be turned into a structured role profile, and say what is missing and what to fix. Takes the job description as text. Runs synchronously — the answer comes back on the same request — so allow a generous client timeout. Metered: see get_account_status.

check_role_status
read

Check whether a role generation has finished, and return the full role profile once it has. Poll this after generate_role.

generate_role
generate

Start generating a structured role profile — description, responsibilities, skills with proficiency levels, qualifications. Returns immediately with a role_id; generation continues in the background, so poll check_role_status. Spends one of this account's role-generation credits. Only one generation runs at a time.

get_account_status
read

Report which WorkforceGPT account this credential belongs to, what it is permitted to do, and how much of its quota is left. Call this first: it is how you find out whether a generation will be accepted before you build one.

get_assessment
read

Fetch one previously run job-description assessment by id.

get_public_role
no account needed

Fetch one published role profile from the public library in full. Needs no account.

get_role
read

Fetch one generated role profile in full, including its skills.

list_my_assessments
read

List this account's recent job-description assessments, newest first, from both this API and the web app.

list_my_roles
read

List the role profiles on this account, newest first.

search_public_roles
no account needed

Search the public WorkforceGPT role library — role profiles their authors chose to publish. Needs no account. Use it for examples of what a generated profile looks like, or for prior art on a title.

Every tool declares its arguments as JSON Schema, served verbatim as MCP's inputSchema, so your client can read the types and the required fields rather than guessing them from prose.

Worked examples

These are argument objects, i.e. what goes in the arguments of a tools/call, or in the body on the plain HTTP path. If you are driving Claude rather than writing a client, you will never type these: they are here so you can see what the agent is actually sending.

Score a job description

{
  "job_description": "Senior Data Analyst\n\nNorthwind is hiring an analyst to own reporting for the commercial team...",
  "filename": "senior-data-analyst.txt"
}

Start a role profile

{
  "role_title": "Data Analyst",
  "company_name": "Northwind",
  "job_description": "Senior Data Analyst\n\nNorthwind is hiring an analyst to own reporting for the commercial team...",
  "use_job_description_if_title_not_found": true,
  "include_learning_resources": true,
  "learning_resources_source": "Skillsoft"
}

Only role_title and company_name are required. The rest are shown here because they are the ones worth knowing about: the job description is what saves a generation when the title does not match labor-market data, and the learning resources are the one place this server offers a choice of source.

Check on it

{ "role_id": 4812 }

Browse the public library

{ "query": "project manager", "limit": 5 }

This one and get_public_role read the published corpus at /roles/. They cost nothing against an account's allowance, and on the plain HTTP path they need no credential at all.

Scopes

Three, and they are what the consent screen shows the person approving your client. Ask for only what you need: a client requesting generate is asking to spend somebody's credits, and they can see that.

read
View your generated roles and JD assessments
assess
Score job descriptions on your behalf
generate
Generate role profiles on your behalf, using your credits

How generation behaves

generate_role does not return a role profile. It starts one and returns a role_id. Poll check_role_status with that id, around every 30 seconds rather than continuously, until the status leaves pending.

How long that takes depends on the role and on load, and we would rather not give you a number we cannot keep. What we can tell you is the ceiling: a generation still running after 60 minutes is marked failed, and a failed generation does not spend a credit.

Only one generation runs per account at a time. Starting a second while one is in flight comes back as generation_in_progress rather than queueing.

assess_job_description is the other way round: it runs synchronously and answers on the same request. It does real work, so give the call a generous client timeout rather than the default few seconds.

Limits

Every refusal tells you which limit you hit, what the account has left, and where to get more. You should not have to work that out from a status code.

Role generations
3 per account
Job description assessments over this API
3 per account
Concurrent generations
1

Assessments run from the web app are free and unmetered; only the API ones are counted, because an agent can loop where a person clicking a button does not. Publishing a generated role to the public library earns the account one extra generation, but publishing is a web-app action. See what it will not do.

Call get_account_status before you plan work. It returns the same quota block that every refusal carries, so you can find out you have nothing left before you build a request rather than after.

When an account runs out

There is no self-serve top-up yet. Talk to TalentGuard and we will sort it out.

What this server deliberately will not do

Publish anything. Roles can be published to a public, search-indexed library at /roles/, under the account holder's name if they choose. That is a decision about someone's public footprint, and it is not one an agent can meaningfully take on their behalf, so there is no tool for it and no scope that would allow it. Publishing happens in the web app or not at all.

Touch an account or anyone else's data. No tool deletes, no tool emails, no tool reaches administrative functions. A credential resolves to exactly one account and sees only what that account owns.

Accept files. MCP tool arguments are JSON, so a job description arrives as text. If you are holding a PDF or a DOCX, extract the text first, or use the web app, which does the conversion for you.

How the connection works

Step one of the quick start is the whole configuration. This is what happens underneath it, which matters if you are writing a client rather than using one.

The server implements OAuth 2.1. Your client's first request is refused with a 401 carrying a WWW-Authenticate header that points at https://workforcegpt.ai/.well-known/oauth-protected-resource. From there it finds the authorization server, registers itself (RFC 7591 dynamic client registration is open, which is why there is no key to paste), and sends the person using it to a consent screen. PKCE is required for every client, including confidential ones.

Authentication is required for every message, including initialize. That is deliberate: the 401 is how a client given nothing but a URL finds everything else, so it has to be the first thing a cold client sees.

The person approving the consent screen must have a WorkforceGPT account with a verified email address. The agent then acts as them, against their quota.

If your client cannot do OAuth discovery

Point it at these directly:

Protected resource  https://workforcegpt.ai/.well-known/oauth-protected-resource
Authorization server https://workforcegpt.ai/.well-known/oauth-authorization-server
MCP endpoint         https://workforcegpt.ai/mcp  (POST, JSON-RPC 2.0)

Supported protocol revisions: 2025-11-25, 2025-06-18, 2025-03-26. If yours is newer, initialize negotiates rather than refusing: it answers with the newest we speak and you decide whether to continue. Every other method answers an MCP-Protocol-Version header we do not know with a 400 naming what we do, which is what the transport spec asks for. ⚠️ The 401 always comes first, so a client on a revision ahead of ours can still discover how to sign in. The server is stateless, i.e. it issues no Mcp-Session-Id, and it offers no server-initiated stream, so a GET asking for text/event-stream is answered 405. So is DELETE, since there is no session to terminate.

Methods: initialize, ping, tools/list, tools/call, and notifications/*, which are acknowledged and not answered. Only tools is advertised under capabilities, with listChanged: false, because the tool set is fixed when the server starts.

A refused tool call is a result, not a protocol error. A spent quota, an unknown id, a bad argument or a missing scope all come back as isError: true with the reason in structuredContent, because the protocol worked and the agent needs to read why. Only an unknown tool name or malformed params is a JSON-RPC error. Treat the first kind as a transport failure and you will hide the message that says what to do next.

Without an MCP client

The same tools are reachable over ordinary HTTP if you are building something that does not speak MCP. Same credential, same quotas, same responses: POST https://workforcegpt.ai/api/v1/mcp/tools/<name> with a JSON object of arguments.

curl -s https://workforcegpt.ai/api/v1/mcp/tools \
  | jq '.tools[] | {name, scope}'

curl -s -X POST https://workforcegpt.ai/api/v1/mcp/tools/get_account_status \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" -d '{}'

The two public-library tools (search_public_roles and get_public_role) need no credential at all on this path. They read the same corpus search engines already index, so you can see what a finished role profile looks like before anyone signs up for anything. This one runs as it stands:

curl -s -X POST https://workforcegpt.ai/api/v1/mcp/tools/search_public_roles \
  -H "Content-Type: application/json" \
  -d '{"query": "project manager", "limit": 5}'

Over MCP itself every tool needs a token, including those two. That is what keeps the 401 bootstrap intact, and a client that has connected has a token anyway.

An account is free to create and comes with 3 role generations.

Create an account

Privacy