Workyard MCP by usefulapi

Read Workyard employees, projects, time cards and geofences; approve time cards and add notes.

Should I use this

Quality & Safety

A
Description quality
96%
Schema completeness
85%
Naming quality
77%
Poisoning risk
100%
Permission match
100%
Protocol compliance
100%

Findings (3)

  • LOWTool 'workyard_list_time_card_activity_segments' description lacks action verbin workyard_list_time_card_activity_segments
  • LOWTool 'workyard_list_time_card_activity_segments' name length outside 3-30 rangein workyard_list_time_card_activity_segments
  • LOWTool 'workyard_list_geofence_projects' name length outside 3-30 rangein workyard_list_geofence_projects

Based on automated analysis of tool definitions and protocol compliance.

Context Cost

~2,579Tokens (tool definitions)
~1.5 KBTypical response size
Significant attention impact (2.01% of 128k context)

This is the approximate number of tokens consumed each time the server's tools are loaded into a model's context. Higher counts reduce the attention available for other tasks.

Install

One-Click Install

Add this to your `claude_desktop_config.json` file:

{
  "mcpServers": {
    "workyard": {
      "url": "https://workyard.usefulapi.io/mcp"
    }
  }
}

Remote endpoints

https://workyard.usefulapi.io/mcpstreamable-http

What it can do

Tool inventory

Tools (12)

🟢 Read-only🟡 Write🔴 Delete⚪ Unknown
🟢workyard_get_organization

The organization this connection uses (id, name, settings such as timezone) from GET /orgs/{org_id}.

Input Schema

{
  "type": "object",
  "properties": {},
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢workyard_list_employees(status, search, email, role_name, employee_id, ...)

List employees of the organization (employee_id, profile_id, name, title, role, status, contact data). Filter by status (active, removed, saas_disabled, expired; comma list), email, role name or free-text search. Paged: use next_page.

Input Schema

{
  "type": "object",
  "properties": {
    "status": {
      "description": "Employee status filter: active, removed, saas_disabled, expired (comma list; sent as eq:...).",
      "type": "string",
      "maxLength": 200,
      "pattern": "^(?:[a-z_]+:)?[A-Za-z_]+(,[A-Za-z_]+)*$"
    },
    "search": {
      "description": "Free-text search over name, email and identifier.",
      "type": "string",
      "maxLength": 200
    },
    "email": {
      "description": "Exact email filter (comma list allowed; sent as eq:...).",
      "type": "string",
      "maxLength": 500
    },
    "role_name": {
      "description": "Role filter: worker, manager, admin (comma list; sent as eq:...).",
      "type": "string",
      "maxLength": 100
    },
    "employee_id": {
      "description": "One or more employee ids, comma separated.",
      "type": "string",
      "maxLength": 300,
      "pattern": "^(?:[a-z_]+:)?[0-9]+(,[0-9]+)*$"
    },
    "page": {
      "description": "Page number, 1-based (default 1). Use next_page from the previous reply.",
      "type": "integer",
      "minimum": 1,
      "maximum": 100000
    },
    "limit": {
      "description": "Results per page, 1-200 (Workyard default 100).",
      "type": "integer",
      "minimum": 1,
      "maximum": 200
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢workyard_list_projects(name, is_archived, include_computed_totals, page, limit)

List projects (id, name, identifier, customer, locations). Optionally filter by name or archived state. Paged: use next_page.

Input Schema

{
  "type": "object",
  "properties": {
    "name": {
      "description": "Project name: a plain name matches names starting with it (like:name%); eq:... and like:... forms are passed through.",
      "type": "string",
      "maxLength": 200
    },
    "is_archived": {
      "description": "true = archived projects only, false = active only (default: Workyard's default).",
      "type": "boolean"
    },
    "include_computed_totals": {
      "description": "Include computed totals per project.",
      "type": "boolean"
    },
    "page": {
      "description": "Page number, 1-based (default 1). Use next_page from the previous reply.",
      "type": "integer",
      "minimum": 1,
      "maximum": 100000
    },
    "limit": {
      "description": "Results per page, 1-200 (Workyard default 50).",
      "type": "integer",
      "minimum": 1,
      "maximum": 200
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢workyard_get_project(project_id)

One project by id (workyard_list_projects gives the ids).

Input Schema

{
  "type": "object",
  "properties": {
    "project_id": {
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991,
      "description": "The project id (org_project_id)."
    }
  },
  "required": [
    "project_id"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢workyard_list_time_cards(status, employee_id, time_approver_id, start_from_unix, start_before_unix, ...)

List time cards (id, employee_id, start_dt_unix, end_dt_unix, status, approver, totals). Workyard returns only status=working when no status is given, so pass status (for example submitted,approved) for finished work. Filter by employee and by start time (unix seconds, interpreted in the organization timezone). Paged: use next_page; the reply also carries time_summary.

Input Schema

{
  "type": "object",
  "properties": {
    "status": {
      "description": "Status filter such as working, submitted, approved or submitted,approved (sent as eq:...). Omitted = working only.",
      "type": "string",
      "maxLength": 200,
      "pattern": "^(?:[a-z_]+:)?[A-Za-z_]+(,[A-Za-z_]+)*$"
    },
    "employee_id": {
      "description": "One or more employee ids, comma separated.",
      "type": "string",
      "maxLength": 300,
      "pattern": "^(?:[a-z_]+:)?[0-9]+(,[0-9]+)*$"
    },
    "time_approver_id": {
      "description": "Filter by approver employee id(s).",
      "type": "string",
      "maxLength": 300,
      "pattern": "^(?:[a-z_]+:)?[0-9]+(,[0-9]+)*$"
    },
    "start_from_unix": {
      "description": "Time card started at or after this unix time (seconds).",
      "type": "integer",
      "minimum": 0,
      "maximum": 4102444800
    },
    "start_before_unix": {
      "description": "Time card started before this unix time (seconds).",
      "type": "integer",
      "minimum": 0,
      "maximum": 4102444800
    },
    "include_last_location": {
      "description": "Include the employee's last known location (personal data).",
      "type": "boolean"
    },
    "sort_by": {
      "description": "Sort in Workyard syntax: asc: or desc: plus start_dt or updated_at, joined with +, e.g. desc:start_dt.",
      "type": "string",
      "maxLength": 80,
      "pattern": "^(?:asc|desc):[a-z_]+(?:\\+(?:asc|desc):[a-z_]+)*$"
    },
    "page": {
      "description": "Page number, 1-based (default 1). Use next_page from the previous reply.",
      "type": "integer",
      "minimum": 1,
      "maximum": 100000
    },
    "limit": {
      "description": "Results per page, 1-200 (Workyard default 50).",
      "type": "integer",
      "minimum": 1,
      "maximum": 200
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢workyard_get_time_card(time_card_id)

One time card by id, with its details (workyard_list_time_cards gives the ids).

Input Schema

{
  "type": "object",
  "properties": {
    "time_card_id": {
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991,
      "description": "The time card id."
    }
  },
  "required": [
    "time_card_id"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢workyard_list_time_card_activity_segments(time_card_id, include_archived_projects)

The activity segments of one time card (where and on which project the employee worked, segment by segment). Not paged.

Input Schema

{
  "type": "object",
  "properties": {
    "time_card_id": {
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991,
      "description": "The time card id."
    },
    "include_archived_projects": {
      "description": "Include segments of archived projects.",
      "type": "boolean"
    }
  },
  "required": [
    "time_card_id"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢workyard_list_geofences(name, enabled, project_id, page, limit)

List geofences / work sites (id, name, place, enabled, radius). Filter by name, enabled state or project. Paged: use next_page.

Input Schema

{
  "type": "object",
  "properties": {
    "name": {
      "description": "Geofence name: a plain name matches names starting with it; eq:... and like:... forms are passed through.",
      "type": "string",
      "maxLength": 200
    },
    "enabled": {
      "description": "Only enabled (true) or disabled (false) geofences.",
      "type": "boolean"
    },
    "project_id": {
      "description": "Only geofences of this project id (comma list allowed).",
      "type": "string",
      "maxLength": 300,
      "pattern": "^(?:[a-z_]+:)?[0-9]+(,[0-9]+)*$"
    },
    "page": {
      "description": "Page number, 1-based (default 1). Use next_page from the previous reply.",
      "type": "integer",
      "minimum": 1,
      "maximum": 100000
    },
    "limit": {
      "description": "Results per page, 1-1000 (Workyard default 1000).",
      "type": "integer",
      "minimum": 1,
      "maximum": 1000
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢workyard_list_active_geofences

All active geofences with limited data (Workyard: GET active_geofences). It does not say who is clocked in; use workyard_list_time_cards with status working for that.

Input Schema

{
  "type": "object",
  "properties": {},
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢workyard_list_geofence_projects(geofence_id, is_archived, page, limit)

The projects attached to one geofence (work site). Paged: use next_page.

Input Schema

{
  "type": "object",
  "properties": {
    "geofence_id": {
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991,
      "description": "The geofence id (workyard_list_geofences gives the ids)."
    },
    "is_archived": {
      "description": "true = archived projects only.",
      "type": "boolean"
    },
    "page": {
      "description": "Page number, 1-based (default 1). Use next_page from the previous reply.",
      "type": "integer",
      "minimum": 1,
      "maximum": 100000
    },
    "limit": {
      "description": "Results per page, 1-200 (Workyard default 50).",
      "type": "integer",
      "minimum": 1,
      "maximum": 200
    }
  },
  "required": [
    "geofence_id"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🔴workyard_approve_time_card(time_card_id)

WRITE: approve ONE time card (PATCH .../time_cards/{id}/approve). Approval feeds payroll in Workyard and may not be undoable through the API: only call it when the user asked to approve this exact time card.

Input Schema

{
  "type": "object",
  "properties": {
    "time_card_id": {
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991,
      "description": "The time card id to approve."
    }
  },
  "required": [
    "time_card_id"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🔴workyard_add_time_card_note(time_card_id, description)

WRITE: add a text note to one time card (POST .../time_cards/{id}/notes). Adds a new note on every call; it does not edit or delete existing notes.

Input Schema

{
  "type": "object",
  "properties": {
    "time_card_id": {
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991,
      "description": "The time card id."
    },
    "description": {
      "type": "string",
      "minLength": 1,
      "maxLength": 4000,
      "description": "The note text."
    }
  },
  "required": [
    "time_card_id",
    "description"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}

Community

Rate this Server

Evidence

Recent observations

verifiedversion not recorded12 tools