Staffing Math

io.github.bsunter93由 GitHub 帳號 bsunter93 發布v0.3.1更新於 Nov 6, 2026

Exact staffing math: FTE needed, a monthly hiring plan, and Erlang C queue staffing.

已驗證Streamable HTTP可網頁執行效率與工作流資料與分析

概覽

AI 產生的概覽

Staffing Math 精確計算所需 FTE、逐月招聘計畫與 Erlang C 排隊人力,並附上輸入與算式。

可以做什麼
  • 依每週業務量、每件分鐘數、損耗率與目標佔用率計算所需 FTE,並無條件進位給出應配置人數
  • 產生逐月招聘計畫,列出每月需開啟的招聘名額,考量成長、流失、招聘時程與上手期
  • 用 Erlang C 為電話或在線客服佇列估算達到應答時間與服務水準目標所需的坐席數
  • 列出每項輸入是已提供或預設假設,並給出代入數字的完整算式
適用情境
當需要回答某項工作量需要多少人、業務量成長時每月該開多少招聘名額,或客服佇列需要多少坐席,並希望得到可複核的算術結果而非估算時使用。
執行需求
可使用託管遠端端點(Streamable HTTP,無需登入),或在本地以 Node 18 以上執行副本(stdio 或置於 HTTPS 後的 HTTP 模式)。未宣告需要 API 金鑰或帳號。
安裝前請注意
工具為唯讀且不儲存資料,但託管伺服器會依日期、應用程式與工具名稱統計請求次數並公開總數;不保存輸入、結果、IP 位址或完整 User-Agent。未提供的輸入會採用預設假設,若未提供真實的損耗率、流失率或現有人數,結果可能造成誤導。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 Staffing Math,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Web executable,透過 Streamable HTTP。 遠端服務在工作區中設定後即可從網頁執行環境執行。

交給代理程式安裝

把這段提示詞貼上到 Claude Code、Codex、Cursor 等代理程式,或 SourceWeft 對話中。代理程式會讀取該伺服器的安裝指南,先向你展示發布者、端點和登入方式,經你同意後再把它新增到你的客戶端。金鑰不會寫進任何命令。

閱讀 https://sourceweft.com/mcp/io.github.bsunter93%2Fstaffing-math/install.md,並按其中說明把這個 MCP 伺服器接入我的客戶端。修改任何設定之前,先告訴我它的發布者、端點和登入方式,等我確認。不要把 API 金鑰寫進命令或我會提交的檔案;問我金鑰應從哪裡取得。

檢視代理程式所依據的安裝指南

其他 MCP 客戶端

把它新增到你客戶端的 mcpServers 設定中。

{
  "mcpServers": {
    "staffing-math": {
      "type": "http",
      "url": "https://staffing-math.vercel.app/mcp"
    }
  }
}

README

Staffing Math

An MCP server that gives Claude and ChatGPT exact staffing math. It has three tools:

  • required_fte: how many people a steady workload needs.
  • hiring_plan: how many requisitions to open each month as volume changes, after attrition, time to hire and ramp.
  • erlang_staffing: how many agents a phone or chat queue needs to hit an answer-time target (Erlang C).

The model does the talking. The tools do every calculation and return it with the answer: each input marked given or assumed, and the arithmetic with the numbers filled in. You can check any answer with a calculator.

In Claude and ChatGPT, hiring_plan also draws its answer: FTE needed against FTE on hand by month, the short months hatched, and the requisitions to open underneath. Sliders for growth, attrition, time to hire, ramp, shrinkage and headcount rerun the plan on the server as you move them, and the model is told what you changed.

The math is the engine from the Operating Model Simulator, copied unchanged into vendor/ along with its own tests.

To use it without installing anything, add https://staffing-math.vercel.app/mcp as a connector. Steps and examples: bensunter.com/staffing-math.html.

Worked example

I handle 4,000 cases a week at 12 minutes each with 30% shrinkage. How many people do I need, and what's my hiring plan if volume grows 5% a month?

required_fte returns:

text
Answer: 33.61 FTE, so 34 people.
Inputs- weekly volume: 4,000 cases (given)- minutes per case: 12 (given)- shrinkage: 30% (given)- target occupancy: 85% (assumed)- hours per FTE per week: 40 (assumed)
Arithmetic1. Work per week = 4,000 cases x 12 min / 60 = 800.0 hours2. Productive hours per FTE = 40 x (1 - 0.3) = 28.00 hours3. Planned hours per FTE at 85% occupancy = 28.00 x 0.85 = 23.80 hours4. FTE needed = 800.0 / 23.80 = 33.615. People to staff = 33.61 rounded up = 34
Each extra minute per case adds 2.80 FTE.

hiring_plan with the same inputs and 5% monthly growth returns this answer and table, plus the same inputs and arithmetic blocks:

text
Answer: open 30 requisitions over 12 months, 4 of them in month 1.FTE needed goes from 33.61 in month 1 to 57.49 in month 12. Expected leavers over the plan: 0.0.Requisitions opened in months 11 and 12 are for hires who count in months 13 and 14, assuming the 5% monthly growth continues.Month 2 is short and new hires can't fix that: the earliest a requisition opened now counts is month 3. Covering it takes overtime, contractors or moving people. People already hired or in the pipeline can count earlier: give them as hires_in_flight.Attrition was assumed to be 0%. At 15% a year this plan needs 38 requisitions; at 30%, 48. Ask for the team's real rate.Current headcount was assumed to be exactly what month 1 needs (34), as if the team is fully staffed today. If it has fewer people, give current_headcount.
MonthWeekly volumeFTE neededReqs to openHires countingExpected leaversFTE on handSpare (+) / short (-)
Month 14,00033.61400.0034.00+0.39
Month 24,20035.29100.0034.00-1.29
Month 34,41037.06240.0038.00+0.94
Month 44,63138.91210.0039.00+0.09
Month 54,86240.86320.0041.00+0.14
Month 65,10542.90220.0043.00+0.10
Month 75,36045.05230.0046.00+0.95
Month 85,62847.30320.0048.00+0.70
Month 95,91049.66220.0050.00+0.34
Month 106,20552.15330.0053.00+0.85
Month 116,51654.75320.0055.00+0.25
Month 126,84157.49330.0058.00+0.51

The prompt didn't give target occupancy, hours per week, current headcount, attrition, time to hire or ramp, so the tool used its defaults and listed each one as assumed. Attrition and headcount move the answer most, so the result spells those two out, with the plan at 15% and 30% attrition alongside. Claude is told to say so and offer to rerun with real numbers. With 30 people today, 25% annual attrition and a month of ramp, the same forecast needs 53 requisitions instead of 30, 12 of them in month 1, and months 1 to 3 are short before any hire can count.

Checking it by hand: month 12 volume is 4,000 x 1.05^11 = 6,841 cases a week. That's 6,841 x 12 / 60 = 1,368 hours, and 1,368 / 23.80 = 57.49 FTE.

Install

The server is one file, dist/staffing-math.mjs, and needs Node 18 or later. Clone the repo first:

bash
git clone https://github.com/bsunter93/staffing-math.git

Claude Desktop

Open Settings, then Developer, then Edit Config, and add the server to claude_desktop_config.json. Use the full path to your clone:

json
{  "mcpServers": {    "staffing-math": {      "command": "node",      "args": ["/full/path/to/staffing-math/dist/staffing-math.mjs"]    }  }}

Restart Claude Desktop. The three tools appear under the tools menu in a new chat.

To install it as a Desktop extension instead, run npm run pack and double-click the staffing-math.mcpb it writes.

Claude Code

As a plugin, from inside Claude Code:

text
/plugin marketplace add bsunter93/staffing-math/plugin install staffing-math@staffing-math

Or as a plain MCP server:

bash
claude mcp add staffing-math -- node /full/path/to/staffing-math/dist/staffing-math.mjs

Gemini CLI

bash
gemini extensions install https://github.com/bsunter93/staffing-math

gemini-extension.json in the repo runs the same bundled server. Gemini CLI shows the tools' text answers; it doesn't draw the plan view.

ChatGPT, Gemini and Claude custom connectors

These connect to a remote server over Streamable HTTP at a public HTTPS URL. The hosted one is free to use and needs no sign-in. It saves none of your numbers; it counts calls by day, app and tool (see Usage counts):

text
https://staffing-math.vercel.app/mcp

To run your own, start the server in HTTP mode:

bash
node dist/staffing-math.mjs --http --port 3000

It listens on http://127.0.0.1:3000/mcp. Put it behind HTTPS (a host, a reverse proxy, or a tunnel such as cloudflared tunnel --url http://localhost:3000), then add https://your-host/mcp as a connector with no authentication:

  • ChatGPT: Plugins, then Add, then Add custom MCP server, with no authentication. ChatGPT draws the plan view. After an update, Refresh tools in the plugin's settings picks up new inputs.
  • Gemini: Connectors, then Custom. Gemini shows the text answers.
  • Claude: Settings, Connectors, Add custom connector. Use --host 0.0.0.0 when it runs on a server.

The HTTP mode is stateless. Each request gets a fresh server, so it scales out without sessions.

Hosting it

api/index.mjs is the same server as a single Web-standard fetch handler (src/fetch.ts), built by npm run build. On Vercel:

bash
npx vercel deploy --prod

vercel.json sends every path to that one function and tells Vercel there's no framework, nothing to install and nothing to build, so a project Vercel once guessed was something else still deploys. .vercelignore uploads only api/ and vercel.json. Dragging a folder with just those two onto the project page in Vercel's dashboard deploys the same thing without the CLI. The endpoint is https://<project>.vercel.app/mcp. The same handler runs on Cloudflare Workers, Deno or Bun. On Workers' free plan, a 36-month plan with attrition can pass the 10ms CPU limit per request; the paid plan doesn't have that problem.

Tools

ToolRequiredOptional, with defaults
required_fteweekly_volume, minutes_per_caseshrinkage 0.30, target_occupancy 0.85, hours_per_fte_week 40
hiring_planminutes_per_case, and weekly_volume (with monthly_growth) or weekly_volume_by_monththe three above, months 12, current_headcount (what month 1 needs), annual_attrition 0, time_to_hire_months 2, ramp_months 0, hires_in_flight (none), start_month
erlang_staffingcontacts_per_hour, handle_time_secondsanswer_within_seconds 20, service_level 0.80, shrinkage 0.30

Fractions are fractions: 0.30 means 30%. A value of 30 for shrinkage is rejected with a message saying so.

Every result has a text block for the model and a structuredContent copy with the same numbers, the inputs and the steps. All three tools are read-only, make no network calls and store nothing.

Usage counts

The hosted server at staffing-math.vercel.app adds one to a counter for each request: the day (UTC), the app (the first word of its User-Agent, such as openai-mcp) and what it asked for (initialize, tools_list, a tool name, or view). It also counts the app name a client sends when it connects. It never saves tool inputs, results, IP addresses or full User-Agent strings. The counts are public at /stats.

Counting runs only when an Upstash Redis REST URL and token are set (KV_REST_API_URL and KV_REST_API_TOKEN, or the UPSTASH_REDIS_REST_ pair). Your own copy, over stdio or HTTP, counts nothing. If the store is slow or down, the answer still goes out; see src/usage.ts.

The plan view

hiring_plan carries an MCP Apps view, ui://staffing-math/hiring-plan.html: one HTML file with its script inlined and no outside requests. Hosts that support MCP Apps draw it under the answer; other hosts ignore it and show the text.

  • The headline and the line under it are the answer in words, and screen readers hear them again after every change.
  • The chart has a text description. Point at a month, or focus the chart and use the arrow keys, to read that month in a sentence.
  • Every control is a labeled native slider or number field, so it works from the keyboard.
  • "Show the numbers" opens the full table.
  • It follows the host's light or dark theme.

The view never calculates. Moving a control calls hiring_plan again with the new arguments and draws what comes back.

How the hiring plan works

  1. FTE needed each month = weekly hours of work / (hours per FTE x (1 - shrinkage) x target occupancy).
  2. Attrition is applied monthly at the rate that compounds to the annual figure: 1 - (1 - annual)^(1/12). Leavers are an expected value, so headcount can be fractional.
  3. A requisition opened in month m counts as capacity from month m + time to hire + ramp. Until it's fully ramped a hire counts as zero, so the plan errs toward opening requisitions early.
  4. Walking forward from the first month a hire can count, wherever FTE on hand is below FTE needed, the solver opens the shortfall in whole people in the month that lands them in time, then reruns the engine.
  5. Months before the first possible landing can't be fixed by new requisitions. The tool says which ones and by how much. People already hired or in the pipeline can: hires_in_flight takes how many and the month each group starts counting, and the plan opens only what's still missing.
  6. Requisitions opened near the end of the plan land after it. With a growth rate the solver carries the forecast past the last month so those requisitions still get planned, and says so. With a month-by-month forecast it plans nothing past the last month you gave.
  7. A month with at least one whole FTE more than it needs is spare. The tool names the most overstaffed month, and the view shades every spare month. Hiring can't fix a spare month; it shows where demand dips below the people already there.
  8. When attrition isn't given, the plan is rerun at 15% and 30% a year and both totals are reported. Those are reference points for the conversation, not benchmarks.

The tests check that the plan covers every coverable month and that removing any single requisition leaves some month short, so it never hires more than the forecast needs.

Where the math comes from

vendor/operating-model-simulator/ is a byte-for-byte copy of the Simulator's engine at commit 758c9d7: the monthly model (run()), Erlang B and C with a stable recursion that doesn't overflow past 170 agents, and the calendar helpers. required_fte and hiring_plan build a one-team model and call run(); erlang_staffing calls staffFor, serviceLevel and erlangC. This repo adds the weekly-to-monthly conversion, the hiring solver and the MCP server around them.

bash
npm installnpm test               # upstream engine tests plus this repo's ownnpm run check:vendor   # confirms vendor/ still matches upstreamnpm run build          # rebuilds dist/staffing-math.mjs

The tests include hand calculations for each tool, a textbook Erlang C written independently to check the engine against, and runs over all three transports: in memory, Streamable HTTP, and the built file over stdio.

Limits

Erlang C assumes nobody hangs up while waiting and that arrivals are steady across the interval, so staff the busiest hour. There's no cost or budget, no multi-team routing, and no seasonality inside a month. The Operating Model Simulator covers multiple teams, routing between them and cost.

License

MIT

來源:README.md,提交 bfeb9f6

工具

3

required_fte

FTE needed for a workload

How many people a steady workload needs. Give weekly volume and minutes per case; shrinkage, target occupancy and hours per week fall back to stated defaults. Returns FTE, people to staff (rounded up), every input marked given or assumed, and the arithmetic with numbers filled in. Use hiring_plan when volume changes over time or the question is about hiring, and erlang_staffing for live queues with an answer-time target.

輸入參數shrinkageweekly_volume必填minutes_per_case必填target_occupancyhours_per_fte_week

hiring_plan

Monthly hiring plan

Month-by-month hiring plan: how many requisitions to open each month so FTE on hand keeps up with FTE needed, after attrition, time to hire and ramp. Give weekly_volume with monthly_growth (0.05 means 5% a month, compounding), or weekly_volume_by_month. Unknown inputs fall back to stated defaults: current headcount defaults to what month 1 needs, attrition to 0, time to hire to 2 months, ramp to 0. When attrition is assumed, the result also gives the plan at 15% and 30%. Give hires_in_flight for people already hired or in the pipeline. Returns the plan table, totals, the arithmetic, and which inputs were assumed. A hire counts as zero capacity until fully ramped.

輸入參數monthsshrinkageramp_monthsstart_monthweekly_volumemonthly_growthhires_in_flightannual_attritionminutes_per_case必填target_occupancycurrent_headcounthours_per_fte_week另有 2 個

erlang_staffing

Queue staffing (Erlang C)

Agents needed on a live queue (phone, chat) to answer a target share of contacts within a target time, using Erlang C. Give contacts per hour for the interval being staffed (usually the busiest hour) and handle time in seconds. Returns agents needed, the service level at that number and at one fewer, chance of waiting, occupancy, and people to schedule after shrinkage. Use required_fte for case or ticket work with no answer-time target.

輸入參數shrinkageservice_levelcontacts_per_hour必填handle_time_seconds必填answer_within_seconds

版本歷史

1
  1. v0.3.1最新Nov 6, 2026

評分

已滿足適用檢查項的 100%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通必需25 分
  • 已宣告認證方式必需10 分
  • 已列出工具必需15 分
  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分