Staffing Math MCP
A community MCP server that calculates FTE requirements, monthly hiring plans, and Erlang C queue staffing needs for contact centers. It allows AI assistants to determine headcount based on workload, shrinkage, and occupancy, and generates hiring schedules to address volume growth and attrition.
Endpoint and access
No sign-in to connect and list tools. Individual tools may still need a vendor account, credentials, or permissions; check the documented prerequisites.
https://staffing-math.vercel.app/mcpWhat its tools do
3 tools, grouped by the hints the server advertises. Hints are self-declared, not verified behavior.
Read-only (3)
Checks and signals
Each line is separate evidence, not a trust score.
- Passed Endpoint answered the live check ·
- Availability 1 of 1 checks passed in 30 days
What you can do with it
- Calculate FTE needed for a specific workload volume
- Generate a monthly hiring plan based on growth and attrition
- Determine agent count for Erlang C queue service levels
Source and maintenance
- Maintenance checked
Protocol and capabilities
- Server
- staffing-math 0.3.1
- MCP protocol negotiated in check
- 2025-11-25
- Tools
- 3 advertised
- Resources
- 1 advertised
- Resource templates
- 0 advertised
- Prompts
- Not advertised
{
"tools": {
"listChanged": true
},
"resources": {
"listChanged": true
}
}Server-provided instructions
Untrusted server output shown for inspection. It is not Koskamo guidance and is excluded from knowledge search.
Tools
3 advertised
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.
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"weekly_volume",
"minutes_per_case"
],
"properties": {
"shrinkage": {
"type": "number",
"maximum": 0.95,
"minimum": 0,
"description": "Share of paid time not available for the work: PTO, sick time, training, meetings. 0.30 means 30%. Default 0.3."
},
"weekly_volume": {
"type": "number",
"maximum": 1000000000,
"description": "Cases, tickets or items arriving per week.",
"exclusiveMinimum": 0
},
"minutes_per_case": {
"type": "number",
"maximum": 10000,
"description": "Average handling time per case, in minutes.",
"exclusiveMinimum": 0
},
"target_occupancy": {
"type": "number",
"maximum": 1,
"minimum": 0.05,
"description": "Share of available time you plan to keep people busy with the work. Default 0.85."
},
"hours_per_fte_week": {
"type": "number",
"maximum": 168,
"description": "Paid hours per full-time person per week. Default 40.",
"exclusiveMinimum": 0
}
}
}{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"fte",
"people",
"weekly_work_hours",
"productive_hours_per_fte_week",
"planned_hours_per_fte_week",
"fte_per_extra_minute",
"answer",
"notes",
"inputs",
"steps",
"engine"
],
"properties": {
"fte": {
"type": "number"
},
"notes": {
"type": "array",
"items": {
"type": "string"
}
},
"steps": {
"type": "array",
"items": {
"type": "string"
}
},
"answer": {
"type": "string"
},
"engine": {
"type": "string"
},
"inputs": {
"type": "array",
"items": {
"type": "object",
"required": [
"name",
"value",
"shown",
"source"
],
"properties": {
"name": {
"type": "string"
},
"shown": {
"type": "string"
},
"value": {
"anyOf": [
{
"type": "number"
},
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "number"
}
}
]
},
"source": {
"enum": [
"given",
"assumed"
],
"type": "string"
}
},
"additionalProperties": false
}
},
"people": {
"type": "number"
},
"weekly_work_hours": {
"type": "number"
},
"fte_per_extra_minute": {
"type": "number"
},
"planned_hours_per_fte_week": {
"type": "number"
},
"productive_hours_per_fte_week": {
"type": "number"
}
},
"additionalProperties": false
}{
"title": "FTE needed for a workload",
"readOnlyHint": true,
"openWorldHint": false,
"idempotentHint": true,
"destructiveHint": false
}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.
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"minutes_per_case"
],
"properties": {
"months": {
"type": "integer",
"maximum": 36,
"minimum": 1,
"description": "Plan length in months when using monthly_growth. Default 12."
},
"shrinkage": {
"type": "number",
"maximum": 0.95,
"minimum": 0,
"description": "Share of paid time not available for the work: PTO, sick time, training, meetings. 0.30 means 30%. Default 0.3."
},
"ramp_months": {
"type": "integer",
"maximum": 24,
"minimum": 0,
"description": "Months from start date to full productivity. Default 0."
},
"start_month": {
"type": "string",
"description": "First month of the plan as YYYY-MM, used only to label months."
},
"weekly_volume": {
"type": "number",
"maximum": 1000000000,
"description": "Weekly volume in month 1. Use with monthly_growth.",
"exclusiveMinimum": 0
},
"monthly_growth": {
"type": "number",
"maximum": 1,
"minimum": -0.5,
"description": "Month-over-month change in weekly volume. 0.05 means 5% a month. Default 0."
},
"hires_in_flight": {
"type": "array",
"items": {
"type": "object",
"required": [
"month",
"count"
],
"properties": {
"count": {
"type": "integer",
"maximum": 100000,
"minimum": 1,
"description": "How many people."
},
"month": {
"type": "integer",
"maximum": 36,
"minimum": 1,
"description": "Plan month the people start counting as capacity. Use 1 for anyone counting from the start."
}
}
},
"maxItems": 36,
"description": "People already hired or in the pipeline, and the month they start counting. These are the only way to cover months before a new requisition can land."
},
"annual_attrition": {
"type": "number",
"maximum": 0.99,
"minimum": 0,
"description": "Share of the team that leaves in a year. 0.25 means 25%. Default 0."
},
"minutes_per_case": {
"type": "number",
"maximum": 10000,
"description": "Average handling time per case, in minutes.",
"exclusiveMinimum": 0
},
"target_occupancy": {
"type": "number",
"maximum": 1,
"minimum": 0.05,
"description": "Share of available time you plan to keep people busy with the work. Default 0.85."
},
"current_headcount": {
"type": "number",
"maximum": 1000000,
"minimum": 0,
"description": "FTE on the team today. Default: what month 1 needs, rounded up."
},
"hours_per_fte_week": {
"type": "number",
"maximum": 168,
"description": "Paid hours per full-time person per week. Default 40.",
"exclusiveMinimum": 0
},
"time_to_hire_months": {
"type": "integer",
"maximum": 24,
"minimum": 0,
"description": "Months from opening a requisition to the start date. Default 2."
},
"weekly_volume_by_month": {
"type": "array",
"items": {
"type": "number",
"maximum": 1000000000,
"exclusiveMinimum": 0
},
"maxItems": 36,
"minItems": 1,
"description": "Average weekly volume in each month of the plan, instead of weekly_volume and monthly_growth."
}
}
}{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"total_reqs",
"first_month_hires_can_count",
"fte_needed_first_month",
"fte_needed_last_month",
"expected_leavers",
"months_short_before_hires_land",
"lookahead_months",
"months_with_spare",
"most_spare",
"attrition_range",
"months",
"answer",
"notes",
"inputs",
"steps",
"engine"
],
"properties": {
"notes": {
"type": "array",
"items": {
"type": "string"
}
},
"steps": {
"type": "array",
"items": {
"type": "string"
}
},
"answer": {
"type": "string"
},
"engine": {
"type": "string"
},
"inputs": {
"type": "array",
"items": {
"type": "object",
"required": [
"name",
"value",
"shown",
"source"
],
"properties": {
"name": {
"type": "string"
},
"shown": {
"type": "string"
},
"value": {
"anyOf": [
{
"type": "number"
},
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "number"
}
}
]
},
"source": {
"enum": [
"given",
"assumed"
],
"type": "string"
}
},
"additionalProperties": false
}
},
"months": {
"type": "array",
"items": {
"type": "object",
"required": [
"month",
"label",
"weekly_volume",
"fte_needed",
"reqs_to_open",
"hires_counting",
"expected_leavers",
"fte_on_hand",
"short_or_spare",
"in_flight"
],
"properties": {
"label": {
"type": "string"
},
"month": {
"type": "number"
},
"in_flight": {
"type": "number"
},
"fte_needed": {
"type": "number"
},
"fte_on_hand": {
"type": "number"
},
"reqs_to_open": {
"type": "number"
},
"weekly_volume": {
"type": "number"
},
"hires_counting": {
"type": "number"
},
"short_or_spare": {
"type": "number"
},
"expected_leavers": {
"type": "number"
}
},
"additionalProperties": false
}
},
"most_spare": {
"anyOf": [
{
"type": "object",
"required": [
"month",
"fte"
],
"properties": {
"fte": {
"type": "number"
},
"month": {
"type": "number"
}
},
"additionalProperties": false
},
{
"type": "null"
}
]
},
"total_reqs": {
"type": "number"
},
"attrition_range": {
"type": "array",
"items": {
"type": "object",
"required": [
"annual_attrition",
"total_reqs"
],
"properties": {
"total_reqs": {
"type": "number"
},
"annual_attrition": {
"type": "number"
}
},
"additionalProperties": false
}
},
"expected_leavers": {
"type": "number"
},
"lookahead_months": {
"type": "number"
},
"months_with_spare": {
"type": "array",
"items": {
"type": "number"
}
},
"fte_needed_last_month": {
"type": "number"
},
"fte_needed_first_month": {
"type": "number"
},
"first_month_hires_can_count": {
"type": "number"
},
"months_short_before_hires_land": {
"type": "array",
"items": {
"type": "number"
}
}
},
"additionalProperties": false
}{
"title": "Monthly hiring plan",
"readOnlyHint": true,
"openWorldHint": false,
"idempotentHint": true,
"destructiveHint": false
}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.
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"contacts_per_hour",
"handle_time_seconds"
],
"properties": {
"shrinkage": {
"type": "number",
"maximum": 0.95,
"minimum": 0,
"description": "Share of paid time agents are off the queue. Converts agents to people scheduled. Default 0.3."
},
"service_level": {
"type": "number",
"maximum": 0.999,
"minimum": 0.01,
"description": "Share of contacts to answer within the target time. Default 0.8."
},
"contacts_per_hour": {
"type": "number",
"maximum": 100000,
"description": "Contacts arriving per hour in the interval being staffed.",
"exclusiveMinimum": 0
},
"handle_time_seconds": {
"type": "number",
"maximum": 36000,
"description": "Average handle time in seconds: talk plus after-contact work.",
"exclusiveMinimum": 0
},
"answer_within_seconds": {
"type": "number",
"maximum": 3600,
"minimum": 0,
"description": "Target answer time in seconds. Default 20."
}
}
}{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"agents",
"service_level_at_agents",
"service_level_one_fewer",
"offered_load_erlangs",
"probability_of_waiting",
"occupancy",
"people_to_schedule",
"answer",
"notes",
"inputs",
"steps",
"engine"
],
"properties": {
"notes": {
"type": "array",
"items": {
"type": "string"
}
},
"steps": {
"type": "array",
"items": {
"type": "string"
}
},
"agents": {
"type": "number"
},
"answer": {
"type": "string"
},
"engine": {
"type": "string"
},
"inputs": {
"type": "array",
"items": {
"type": "object",
"required": [
"name",
"value",
"shown",
"source"
],
"properties": {
"name": {
"type": "string"
},
"shown": {
"type": "string"
},
"value": {
"anyOf": [
{
"type": "number"
},
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "number"
}
}
]
},
"source": {
"enum": [
"given",
"assumed"
],
"type": "string"
}
},
"additionalProperties": false
}
},
"occupancy": {
"type": "number"
},
"people_to_schedule": {
"type": "number"
},
"offered_load_erlangs": {
"type": "number"
},
"probability_of_waiting": {
"type": "number"
},
"service_level_at_agents": {
"type": "number"
},
"service_level_one_fewer": {
"type": [
"number",
"null"
]
}
},
"additionalProperties": false
}{
"title": "Queue staffing (Erlang C)",
"readOnlyHint": true,
"openWorldHint": false,
"idempotentHint": true,
"destructiveHint": false
}Prompts
Not advertised
Resources
1 advertised
Hiring plan view
Chart of FTE needed against FTE on hand by month, with requisitions to open and controls that rerun the plan.
ui://staffing-math/hiring-plan.html90-day uptime
A lightweight connection check about every six hours, sampled on hosts with many listings. It shows the server answered, not that its tools work.
- 2026-11-07: 2 of 2 checks answered
- 2026-11-09: 1 of 1 checks answered
30-day availability
Aggregated from read-only remote checks; this is not a tool-execution or security guarantee.
- Successful checks
- 1 of 1 (100%)
- Average latency
- 645 ms
- 95th percentile latency
- 645 ms
Maintenance history
Public check and source-refresh events. Editorial and ownership records remain private.
- · probe · passed · 645 ms · metadata changed · 3 tool(s), 1 resource(s), 0 resource template(s)
Connect from your client
Each snippet registers the same endpoint; pick the client you use.
Claude Code
claude mcp add --transport http staffing-math-mcp https://staffing-math.vercel.app/mcpCodex
codex mcp add staffing-math-mcp --url https://staffing-math.vercel.app/mcpCursor
{
"mcpServers": {
"staffing-math-mcp": {
"url": "https://staffing-math.vercel.app/mcp"
}
}
}Cline
{
"mcpServers": {
"staffing-math-mcp": {
"type": "streamableHttp",
"url": "https://staffing-math.vercel.app/mcp",
"disabled": false
}
}
}VS Code
{
"servers": {
"staffing-math-mcp": {
"type": "http",
"url": "https://staffing-math.vercel.app/mcp"
}
}
}Gemini CLI
gemini mcp add --transport http staffing-math-mcp https://staffing-math.vercel.app/mcpClaude Desktop
https://staffing-math.vercel.app/mcpWindsurf
{
"mcpServers": {
"staffing-math-mcp": {
"serverUrl": "https://staffing-math.vercel.app/mcp"
}
}
}Let your agent find its tools
Find servers like Staffing Math MCP from your agent. Add Koskamo once to search the index for endpoints, access requirements, and client setup. Public discovery needs no key.