Skip to main content
Glama
dragosh29

WorkMobile MCP server

by dragosh29

WorkMobile MCP server

An MCP server that lets Claude, ChatGPT and other MCP clients work with a WorkMobile account: jobs dispatched to field staff, job types, forms and the records submitted on them, approvals and mobile users, and (when enabled) creating and allocating jobs and approving or rejecting records. It is built from WorkMobile's public documentation only: the Web API v2 OpenAPI spec, the WorkMobile help centre's API 2.0 articles, and the Power Automate connector definition that eSAY Solutions Ltd publishes (the source of the response schemas; the v2 spec has none for these endpoints).

Once it's connected, someone in the office can ask things like:

  • "Which jobs are booked for Sam tomorrow, and which are still unallocated?"

  • "Show me the history of job 70001."

  • "What came in on the Gas Meter Inspection form this week where the meter type was Gas or Water?"

  • "What's waiting for my approval on the Customer Visit Record form?"

  • With writes enabled: "Raise a meter read job at 3 Example Lane for Friday and give it to Sam", "Approve record 30000 on the inspection form."

Tools

Tool

What it does

API calls

list_jobs

Searches jobs by status IDs, estimated start date range, the mobile users they are allocated to, job types, description, priority, backlog and whether a duration is set; optional sort by estimated start. Pages of 500 (the smallest page size the API allows). A POST that only reads.

POST /api/jobs/search

get_job

One job: description, status, type, priority, dates, allocation, history (status changes with narrative) and job data.

GET /api/jobs/{id}

list_job_statuses

WorkMobile's static list of job status IDs, returned as WorkMobile sends it (the format is not documented).

GET /api/jobs/jobstatuslist

list_job_types

Job types with the form each uses, default duration and location settings.

GET /api/jobtypes

get_job_type

One job type and the fields a job of that type takes (name, type, required, allowed values, limits), read from its JSON Schema document.

GET /api/jobtypes/{id}, GET /api/jobtypes/{id}/schema

list_forms

Forms visible to the API user (sub-forms hidden unless asked). The API returns the whole list without paging.

GET /api/forms

list_form_submissions

Searches the records submitted on one form by created or uploaded date, job, mobile user, user group, or searchable field values with the documented operators; newest first by default. Pages of 500. A POST that only reads.

POST /api/forms/{FormId}/completedrecords/search

get_form_submission

One record by its Id (the search's id criterion).

POST /api/forms/{FormId}/completedrecords/search

list_approvals

Without form_id: the API user's approval inbox totals, returned as sent (format not documented). With form_id: the records on that form pending the API user's approval (onlyMyPendingApprovals).

GET /api/approvals/getinboxtotals or the records search

list_mobile_users

Field staff with name, job title, user group name and whether active (inactive users hidden unless asked).

GET /api/mobileusers, GET /api/usergroups

create_job

Raises a job of one type, optionally allocated to one mobile user. Fetches the job type's schema first and refuses locally when a data field is unknown, a required field is missing, a value is not an allowed one, a numeric field gets text, or only one of latitude/longitude is given. Only registered when writes are enabled.

GET /api/jobtypes/{id}/schema, POST /api/jobs (multipart form)

allocate_job

Allocates or reallocates a job to one mobile user, replacing any previous allocation. Marked destructive. Writes only.

POST /api/jobs/{JobId}/allocate/{MobileUserId}

approve_record

Approves the current approval step of a record as the API user. Cannot be undone. Marked destructive. Writes only.

POST /api/approvals/approve

reject_record

Rejects a record's current approval step. Rejection is terminal: the workflow stops for good. Marked destructive. Writes only.

POST /api/approvals/reject

The v2 API is the whole web application's API (158 operations). Not covered on purpose: the username/password login (/api/account/authenticate) and every other account, password, SSO and API-token route; CRM customers and contacts and lone worker event logs (their read endpoints exist, but WorkMobile publishes neither a response schema nor an example for them, so their field names would have to be guessed); record revision and approval history (same reason); reports, media attachments, resources and every other download; track-worker locations; notification history; filtered views, menus and push notifications; user (portal login) management; job editing, closing, unallocation, group broadcast and routing; and every delete endpoint.

Related MCP server: Amiqus MCP server

Setup

Requires Node 18 or later.

npm install
npm run build

You need an API token for your WorkMobile account. WorkMobile's help centre recommends it for unattended use: create a portal user with suitably limited access on the Logins page, then click Generate in its API Token section and copy the GUID. The token gives non-expiring access until it is revoked or regenerated. The server sends it in the X-API-Key header on every request; it never uses a username or password.

Claude Desktop: add this to claude_desktop_config.json:

{
  "mcpServers": {
    "workmobile": {
      "command": "node",
      "args": ["/absolute/path/to/workmobile-mcp/dist/index.js"],
      "env": { "WORKMOBILE_API_KEY": "your-api-token" }
    }
  }
}

Claude Code:

claude mcp add workmobile -e WORKMOBILE_API_KEY=your-api-token -- node /absolute/path/to/workmobile-mcp/dist/index.js

Variable

Required

Meaning

WORKMOBILE_API_KEY

yes

The API token (a GUID) of a portal user, sent as the X-API-Key header.

WORKMOBILE_ALLOW_WRITES

no

true to register create_job, allocate_job, approve_record and reject_record. Off by default.

WORKMOBILE_BASE_URL

no

Defaults to https://www.esayworkmobile.co.uk/webapi2. Used by the tests; an on-premise instance would set its own. Must not contain a username or password.

Safety defaults

  • Read-only unless WORKMOBILE_ALLOW_WRITES=true. Every read tool carries the MCP readOnlyHint annotation, including the ones that call a search endpoint with POST (list_jobs, list_form_submissions, get_form_submission, and list_approvals with a form_id): WorkMobile runs its job and record searches as POST requests with a criteria body, and they change nothing. allocate_job (it replaces the job's current allocation), approve_record and reject_record (they move an approval workflow on for good) carry destructiveHint: true, since MCP reserves false for tools that only add; create_job, which only adds a job, is a write that is not destructive.

  • Personal data is withheld by default and returned only when a tool is called with include_contact_details=true:

    • Job data and form answers are keyed by the account's own field names, so fields are classified by name. A field whose name mentions an email, phone, mobile or "mob", postcode, address, street, what3words, customer, client, tenant, resident, patient, witness, next of kin, name (any "name", so "Site Name" too), signature, photo, image, sketch, video, audio, attachment or file, location, GPS, latitude/longitude, date of birth (including "DoB" and "D.O.B"), passport, NHS or national insurance number (including "NINumber" and "NINo"), vehicle registration, injury, medical, medication, allergy, disability, illness or diagnosis, salary, wage, earnings, overtime, pay, paid or rate, or contact/person/owner/driver is replaced with [withheld: personal data; …]. Names are matched in any style: PascalCase unique names as WorkMobile's documentation writes them ("MeterType"), acronyms ("GPSCoords"), and labels with spaces, dots or hyphens. "Health" alone is not a trigger, because "Health and Safety" fields are common in field-service forms. Nested values are checked the same way.

    • A job's Location (its address) is withheld; a mobile user's Username (often an email address) is not returned.

    • In every other text (job descriptions and history narratives, answers in fields with ordinary names, names and job titles, form descriptions, job type names, WorkMobile's own error messages, the job status list, the approval inbox totals) email addresses become [email redacted], phone-number-like sequences [phone redacted], latitude/longitude pairs [location redacted] and UK postcodes [postcode redacted]. The phone match is the same heuristic as the other prototypes: international numbers with + or 00, UK numbers with a bracketed area code, and UK-style 0… numbers of 9 to 11 digits; other digit strings starting with 0 are caught too. The postcode match is upper case only. People's names and street addresses written in free text are not recognised: "lives at 14 Example Road" comes back as written (only a postcode after it is redacted), and so does a customer's name in a job description or history narrative.

    • A value that is a bare link (http… or www.…) in job data or form answers is withheld, because it may point to a photo, signature or file.

    • Staff names are returned: mobile users' names, CreatedBy on records and job history, and the approval columns of a record. A record's Customer column, like any field with "customer" in its name, is withheld. A system column (such as CreatedBy or UserGroup) or a job Location that arrives as an object or an array rather than text is walked like job data: its keys are classified by name and its text redacted.

  • Never returned, whatever is asked: fields whose name mentions a bank, sort code, IBAN, SWIFT/BIC, account number ("Acc No", "Acct"), card, CVV/CVC, expiry, PAN, last 4 or last four, or payment; any 13-to-19-digit number that passes the Luhn check in any text (replaced with [card number redacted]); in any text, an IBAN that passes its mod-97 check, and a sort code, account number or card's last four digits when the words in front name them ("sort code 12-34-56", "acct 12345678", "card ending 4242") (replaced with [bank details redacted]; a bare 6- or 8-digit number is left alone); and any embedded file (a data: URI, as a signature or photo could be sent) (replaced with [embedded file omitted; files are never returned]). No file is ever downloaded: the server never calls the report, media, resource or download endpoints.

  • IDs are checked before any call is made: every ID must be a whole number from 1 to 2147483647 (the spec types them as int32, except FormId in the path of the records search, which it types as a string; form IDs are int32 everywhere else). Dates take YYYY-MM-DD (real calendar dates only; an impossible month or day is refused with "Not a real calendar date"), which becomes the start of that day in UTC for a "from" and the end for a "to", or an ISO 8601 date-time with a zone (Z or an offset) and an hour from 00 to 23, as in WorkMobile's documented examples. Field filter operators must be one of the eleven the search documentation lists.

  • WorkMobile does not document a rate limit (nothing in the v2 spec, the connector definition or the help centre's API 2.0 articles). Requests are spaced 250 ms apart (about four per second). A 429 is retried at most twice for any method, on the assumption that a rate-limited request was not processed, waiting for Retry-After (whole or fractional seconds, or an HTTP-date; 2 s then 4 s when the header is absent or unreadable). Each wait is capped at 10 seconds; if WorkMobile asks for a longer wait the call gives up at once and the message says how long to wait. A tool call that makes several requests (up to 10 pages) can still run past the MCP client's default 60-second request timeout.

  • 502, 503 and 504 are retried the same way for GET only; when all three attempts fail the error says the service may be unavailable, without the gateway's HTML. No POST is ever retried after a gateway error. For the searches the message says the search only reads, so calling the tool again is safe; for a write it says the request may already have been processed and names the tool to check with (list_jobs, get_job or list_approvals) before repeating it.

  • A 200 whose body is not JSON (a proxy or a login page in the way) is reported as an error naming WORKMOBILE_BASE_URL, never as an empty list; the body is described by type and size, never quoted. A search that answers with anything other than a JSON array of rows is reported with the key names it got, never read as empty. The connector definition types the job search answer and the job type schema document as strings, so a JSON array or object sent double-encoded (as a JSON string holding JSON text) is decoded once; any other string is still refused. A single-record GET answering 200 with null or an empty object is reported as not found.

  • A rejected API key (401) produces a message that says which variable to fix and where the token comes from; a 403 names the roles WorkMobile's documentation lists for the API user; a 400 passes on WorkMobile's title, detail and field errors when the body is ProblemDetails JSON. The API key is scrubbed from every error message, and contact details are redacted from WorkMobile's error text.

Tests

npm test

The spec (spec.json, from https://www.esayworkmobile.co.uk/webapi2/swagger/v2/swagger.json) and the connector definition (connector.json, from microsoft/PowerPlatformConnectors, certified-connectors/WorkMobile/apiDefinition.swagger.json, publisher eSAY Solutions Ltd) are downloaded on the first run if they are missing. Both are gitignored.

Where the schemas come from:

  • Request bodies: the v2 spec's own component schemas (JobSearchCriteria, CompletedRecordsSearchCriteria, ApproveRequest, RejectRequest, all with additionalProperties: false) and its multipart schema for POST /api/jobs. One substitution: the spec's UserDefinedFieldFilter is an object with no properties and additionalProperties: false, so it accepts only {} and would reject every documented filter example; filter items are validated against the spec's UserDefinedFieldFilterDefinition (uniqueName, operator, value, …) instead, and record search bodies without filters are validated against the unmodified schema.

  • Responses of forms, job types, jobs, mobile users and user groups: the connector definition's response schemas. The help centre's documented GET /api/Forms example shows "LastUpload": null where the connector types a string, so that one field is allowed to be null.

  • Job search rows: WorkMobile documents the response only as "the list of jobs that meets the criteria". The mock answers a bare JSON array of objects shaped like the connector's GET /api/Jobs/{id} schema; this is an assumption.

  • Completed records: WorkMobile publishes neither a schema nor an example. test/schemas.mjs holds a schema written by hand from what is documented (the numeric Id, OriginalId and JobId columns the search documentation filters and sorts on, and the Created and CreatedBy static fields of the documented form example), with every other key taken to be one of the form's fields by unique name. The whole row shape, and the bare-array envelope, are assumptions.

  • Job type schema document: the help centre's sample, copied verbatim (test/doc-examples.mjs) and served as job type 10238; the two documented GET /api/Forms examples are served verbatim too.

  • Job status list, approval inbox totals, error bodies, write replies: not documented; the mock's placeholders are listed at the top of test/mock-server.mjs. The tools that return the first two pass them through without relying on any field name.

The test suite (28 checks):

  1. Validates every fixture against those schemas, reports any fixture key the connector schema does not declare, confirms the documented examples are served unchanged, and runs negative controls (a string JobId, a record without OriginalId, an undeclared key). Checks the field-name classifier on its own against personal, financial and ordinary names in PascalCase, acronym, dotted and spaced forms, and the bank-detail text patterns.

  2. Starts a local mock of the API under /webapi2 that requires the X-API-Key header (401 "Unauthorised" without it or with a wrong key), serves 1,100 jobs and 620 records on one form in pages of 500 with the documented pagination body (refusing a rowCount below 500, and a record search without orderBy, which the help centre says is always required), answers unknown IDs with a 404 and bad requests with a 400 as ProblemDetails, and answers the first GET /api/forms with a 429. The mock's list and detail responses are validated against the schemas above.

  3. Starts the built server and drives it over stdio with the official MCP client: tools/list and annotations; every read tool; job search pagination across three pages to the short last page, continuation from next_page, and the note when rows of a fetched page are not returned; every documented job search filter and the record search criteria (created and uploaded dates, job, mobile user, user group, field filters with AND/OR, sort order) sent exactly as documented, in bodies validated against the spec; redaction by default (in list_jobs, get_job, list_form_submissions, get_form_submission, list_approvals with a form_id, list_mobile_users, list_forms and the approval inbox totals: personal fields by name, including DoB, D.O.B, NINumber, What3Words and Mob No, a bare link, emails, phone numbers, postcodes and coordinates in text) and its return on request (in get_job, get_form_submission, list_approvals and list_mobile_users), with bank and card fields, a Luhn-valid card number, a sort code, an account number and an IBAN typed into text, and an embedded image withheld even on request; object- and array-valued system columns and an object Location redacted like job data; a double-encoded job type schema (read by get_job_type and used by create_job) and job search answer decoded; the write tools absent with WORKMOBILE_ALLOW_WRITES unset and set to false; create_job posting a multipart form whose fields are all in the spec's schema and validate against it, with Data as {"jobData": …}, and refusing unknown fields, missing required fields, disallowed values, text for a numeric field and half a location before any POST; allocate_job, approve_record and reject_record bodies validated against the spec, and a 400 passed on; invalid IDs, dates (including month 13, 30 February and hour 24, with the validation message checked) and operators refused with no request made; the 404 message for unknown job and job type IDs and a 200 null or {} job read as not found; requests of a paged search spaced by the 250 ms throttle, and paging stopping once max_results rows are in hand; the 429 retry waiting for Retry-After in the seconds, fractional-seconds and HTTP-date forms and the 2 s fallback when the header is absent, retrying a POST with the same body (page 2 of a three-page search asked for again with no row lost or duplicated, and a rate-limited POST /api/jobs creating exactly one job), giving up after three attempts on a persistent 429 and at once on a Retry-After above the cap; a 502 retried for a GET and never for a POST search or write, with the right advice in each case; three 503s on a GET reported without HTML; a non-JSON 200, a search answer that is not an array, and a 403 (whose body echoing the API key and an email address reaches the tool result scrubbed); the 401 message for a wrong key, after exactly one request; and, last, that every request carried X-API-Key (the configured one, except the deliberate wrong-key call) and no Authorization header, matched exactly one method and path documented in the spec (integer path parameters match digits only, so a parameter cannot stand in for a literal segment), sent a body content type the spec accepts for that operation, and never touched a login, download, media or report endpoint.

The suite takes about 35 seconds.

Status

This is a working prototype. It has not been run against the live API, because it was built without a WorkMobile account (trials are set up through WorkMobile's sales team). Everything below comes from the published documentation and should be confirmed on a real account:

  • The response of POST /api/jobs/search and POST /api/forms/{FormId}/completedrecords/search: that each page is a bare JSON array (not an object with the rows and a total, and not the JSON string the connector definition types the job search answer as; a double-encoded array is decoded, but that path has only been tried against the mock), that job rows carry the same fields as GET /api/jobs/{id}, and that a page with fewer than 500 rows is the last. If the envelope differs, the server says so with the key names it got rather than guessing.

  • The shape of a completed record: that Id, OriginalId and JobId are columns with those names, which other system columns exist and what they are called, and that the form's fields are keyed by unique name with scalar values. Also how photos, signatures, sketches and locations appear in a record (a link, an ID, embedded data), so the name- and value-based withholding can be checked against real data.

  • Whether the record search criteria are sent as arrays (createdDateFrom: ["…"], id: [21524]), as the current spec types them, or as the single values the 2021 help centre article shows; and how userDefinedFilter items are really read, given the spec's empty UserDefinedFieldFilter schema.

  • Which time zone WorkMobile applies to the search dates. The server sends UTC (…Z), as the documented examples do; the timestamps in the documented responses carry no zone.

  • Whether GET /api/jobtypes/{id}/schema returns the JSON Schema document as an object (as the help centre sample shows) or as a JSON string holding it (as the connector types it); both are handled, only against the mock. And whether a job's Location is ever an object rather than the connector's string.

  • What the API answers for an unknown job, job type or form ID (the spec lists only 200 and 401 for these GETs); the server handles a 404 and a 200 with null or {}.

  • The format of GET /api/jobs/jobstatuslist and GET /api/approvals/getinboxtotals (returned as sent, with text redaction), and the IDs of the nine documented statuses.

  • The error bodies: whether 400s come as ProblemDetails, and whether 401 and 403 carry anything. What a 403 looks like for a portal user that lacks a role.

  • POST /api/jobs: that Data is the JSON document {"jobData": {…}} (the documented JSON Schema describes an object with a jobData property), that AllocatedMobileUserId and AllocatedUserGroupId of 0 mean unallocated (as the connector says), what Priority values and Duration unit are valid, that EstimatedStart accepts a UTC date-time, and that the reply is the new job ID as an integer (as the connector types it). The local check of job data covers only unknown fields, required fields (marked, as in the documented sample, by a required array holding the field's own name), allowed values and numeric types; WorkMobile's own validation is the authority.

  • The replies of allocate (typed as a string by the connector), approve and reject (documented only as "Success"), and what approve/reject answer for a record with no step pending for the API user.

  • Whether a 429 on a POST means the request was not processed (the retry assumes so), and how many requests per second the API tolerates; nothing is documented, so the 250 ms spacing is a guess on the polite side.

  • The roles the API user needs for each tool; the 403 message quotes role names from the example token in WorkMobile's authentication article.

Going to production

This version runs locally over stdio, with the account holder's own API token. For customers to connect from claude.ai or ChatGPT without handling tokens, the next step is a remote server (Streamable HTTP) behind OAuth, hosted by eSAY Solutions, and then a listing in the Claude and ChatGPT connector directories. A production version would also cover what this one leaves out for lack of documented response shapes (CRM customers and contacts, lone worker events, record history), once those shapes are confirmed.

Licence

MIT. Built by Alexandru Dragoș (alexandru.dragos96@gmail.com) with an AI agent (Claude) working under his direction.

Available Tools

10 tools
get_form_submissionGet a submitted form recordA
Read-onlyIdempotent

One record submitted on a form, found by its record Id (the search criterion id of POST /api/forms/{FormId}/completedrecords/search): system columns and answers. Unless include_contact_details is set, answers in fields whose names mark them as personal and links to media are withheld; in other answers, emails, phone numbers, postcodes and coordinates are redacted, but names and street addresses typed into free text are not. Files and media are never downloaded.

ParametersJSON Schema
NameRequiredDescriptionDefault
form_idYesForm ID (a positive whole number)
record_idYesRecord ID (a positive whole number)
include_contact_detailsNoInclude personal answers and links to media (never downloaded), and stop redacting emails, phone numbers, postcodes and coordinates in other answers. Off by default. Bank, card and payment details are never returned.

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare read-only/idempotent/non-destructive, and the description adds substantial extra context: the exact redaction policy, that personal-named fields and media links are withheld unless include_contact_details is set, that free-text names/addresses are not redacted, and that files/media are never downloaded. This is real behavioral disclosure beyond the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the purpose and key lookup key, then spends its length on genuinely useful redaction semantics. The middle sentence is dense but every clause carries actionable information; only minor tightening is possible.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only single-record getter with no output schema, the description covers what is returned (system columns and answers), how to address the record, and the privacy/redaction behavior an agent must anticipate.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds meaning beyond the schema for include_contact_details (what it un-redacts, what is never returned, and the free-text caveat) and clarifies that record_id is the search criterion `id`.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('One record submitted on a form'), and the lookup key (record Id). The singular/one-record framing clearly distinguishes it from the sibling list_form_submissions.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives useful context on how a record Id is obtained (the `id` search criterion of the completedrecords/search endpoint), which implies usage, but never explicitly says when to choose this over list_form_submissions or other siblings, and gives no exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_jobGet jobA
Read-onlyIdempotent

One job by ID: description, status, type, priority, dates, allocation, its history (status changes with narrative) and its job data (the fields of the job's form). Unless include_contact_details is set, the job location and job data fields whose names mark them as personal (names, contact details, addresses, signatures, photos, locations) are withheld; in the description, the history narratives and other fields, emails, phone numbers, postcodes and coordinates are redacted, but names and street addresses written in that free text are not. Uses GET /api/jobs/{id}.

ParametersJSON Schema
NameRequiredDescriptionDefault
job_idYesJob ID (a positive whole number)
include_contact_detailsNoInclude the job location and personal fields in the job data, and stop redacting emails, phone numbers, postcodes and coordinates in text. Off by default. Bank, card and payment details are never returned.

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the readOnly/idempotent annotations by disclosing the redaction model in detail: which fields are withheld without include_contact_details, that bank/card/payment data is never returned, and the important nuance that free-text names and street addresses are NOT redacted even when the flag is off. This is exactly the kind of non-obvious behavior an agent must know before interpreting results.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose is front-loaded in the opening clause, followed by the return contents and then the caveat. Sentence two is long and dense but every clause carries distinct information; the closing API-path note is slightly redundant but harmless.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema and only two parameters, the description compensates well by enumerating return contents and the redaction rules, so an agent knows what to expect back. It is only marginally short of complete: it does not mention error or not-found behavior, and the endpoint reference is the least useful part.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds meaning the schema does not: the precise scope of what include_contact_details un-redacts in text (emails, phone numbers, postcodes, coordinates) versus what stays exposed regardless (free-text names and addresses). That is genuine semantic value beyond the schema's 'Include the job location and personal fields' phrasing.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('One job by ID') and enumerates the returned content (description, status, type, priority, dates, allocation, history, job data), which clearly separates it from the sibling list_jobs and the list_* utilities. An agent can select this tool without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The 'One job by ID' framing implies the single-record retrieval context versus the sibling list_jobs, but the description never states when to prefer this over list_jobs or what to do when the ID is unknown/not found. Usage is implied rather than explicitly guided.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_job_typeGet job typeA
Read-onlyIdempotent

One job type (GET /api/jobtypes/{id}) and the fields a job of this type takes, read from its JSON Schema document (GET /api/jobtypes/{id}/schema): name, type, whether required, allowed values and limits. Call this before create_job.

ParametersJSON Schema
NameRequiredDescriptionDefault
job_type_idYesJob type ID (a positive whole number)

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, so the safety profile is covered. The description adds real value beyond that by disclosing that it aggregates two API calls and returns the field-level schema (required flags, allowed values, limits), which the agent would not otherwise expect from a plain 'get'.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

One dense sentence that front-loads the resource and ends with the actionable directive. The inline endpoint paths are slightly noisy but do convey where the data originates, so little is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description compensates by enumerating what is returned — name, type, required, allowed values, limits — and it explains the prerequisite relationship with create_job. Nothing an agent needs to call this correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single job_type_id parameter is fully documented in the schema (100% coverage, positive integer with bounds), so the schema carries the load. The description adds no format or semantic detail beyond what the schema already states, which is the expected baseline for a fully-documented parameter.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('One job type') and goes further by naming the exact endpoints it consumes (GET /api/jobtypes/{id} and /{id}/schema). This clearly separates it from the sibling list_job_types.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit when-to-use directive: 'Call this before create_job.' It does not, however, distinguish itself from list_job_types or state the case where you already know the schema (skip the call), so it stops short of full routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_approvalsPending approvalsA
Read-onlyIdempotent

Without form_id: the API user's approval inbox totals (badge counts) from GET /api/approvals/getinboxtotals, returned as WorkMobile sends them with text redacted (the format is not documented). With form_id: the records on that form waiting for the API user's approval (records search with onlyMyPendingApprovals), with personal answers withheld unless include_contact_details is set.

ParametersJSON Schema
NameRequiredDescriptionDefault
pageNoPage to start from (pages hold 500 rows, the smallest page size the API allows)
form_idNoList the records on this form that are pending the API user's approval
max_pagesNoPages of 500 to fetch in this call
max_resultsNoMost rows to return; rows beyond this on pages already fetched are counted, not returned
include_contact_detailsNoInclude personal answers in the pending records. Off by default. Bank, card and payment details are never returned.

TDQS

A4.1/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare the read-only, idempotent, non-destructive, open-world profile, and the description adds substantial behavior beyond them: totals come back as WorkMobile sends them with text redacted and an undocumented format, and record answers are withheld unless include_contact_details is set. The explicit warning that the totals format is undocumented is exactly the kind of caveat an agent needs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two front-loaded sentences, each covering one mode, with no filler. It is dense with implementation references (GET /api/approvals/getinboxtotals, onlyMyPendingApprovals) that are useful but slightly noisy for an agent. Well structured but not maximally crisp.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description correctly steps in to describe what each mode returns, including the redaction of text and answers and the never-returned bank/card/payment fields. Pagination details live in the schema. It is largely complete for this tool; only return-shape specifics for the undocumented totals format are left open (by necessity).

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents page, form_id, max_pages, max_results, and include_contact_details, including the max_results counting nuance. The description reinforces form_id's mode-switching role and the include_contact_details withholding behavior, but adds little the schema does not already say. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description gives a specific verb+resource and, unusually, splits the tool's purpose by mode: without form_id it returns approval inbox totals (badge counts), with form_id it returns the records awaiting the API user's approval. That is precise and unambiguous. It does not explicitly differentiate the tool from siblings like list_form_submissions, so it stops short of a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives an explicit conditional rule for which mode to use: omit form_id for inbox totals, supply form_id for the pending record list. That is clear when-to-use guidance. It does not name alternative sibling tools or say when this tool is the wrong choice, so it is not a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_formsList formsA
Read-onlyIdempotent

Forms visible to the API user (GET /api/forms): ID, name, description, whether live and visible on mobile, whether it is a sub-form, and when data was last uploaded. The API returns the whole list without paging.

ParametersJSON Schema
NameRequiredDescriptionDefault
live_onlyNoOnly live forms
include_subformsNoInclude sub-forms

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent and non-destructive behavior, so the safety profile is covered. The description adds the meaningful detail that 'the API returns the whole list without paging', which is a real behavioral trait not captured by annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single dense sentence front-loads the endpoint, scope, and return fields with no filler. Every clause carries information an agent can act on.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description compensates by enumerating the returned fields and disclosing the no-paging behavior. Only minor gaps remain (ordering, size expectations), but the definition is complete enough to call correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so both parameters (live_only, include_subforms) are already documented in the schema. The description adds no syntax or semantic detail beyond that, making the baseline 3 appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Forms visible to the API user'), names the exact endpoint (GET /api/forms), and enumerates the returned fields. This clearly distinguishes it from siblings like list_form_submissions and get_form_submission.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The scoping phrase 'visible to the API user' and the two optional flags imply the filtering use case, but there is no explicit when-to-use, when-not-to-use, or named alternative among the many sibling list tools. Usage is inferred rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_form_submissionsSearch submitted form recordsA
Read-onlyIdempotent

Search the records submitted on one form (POST /api/forms/{FormId}/completedrecords/search): by created or uploaded date, job, mobile user, user group, or searchable field values. Each record comes back with its Id, OriginalId and JobId, the system columns, and the answers. Unless include_contact_details is set, answers in fields whose names mark them as personal (names, contact details, addresses, postcodes, signatures, photos, locations, dates of birth, health, pay) and links to media are withheld; in other answers, emails, phone numbers, postcodes and coordinates are redacted, but names and street addresses typed into free text are not. This search is a POST request that only reads. Pages hold 500 records.

ParametersJSON Schema
NameRequiredDescriptionDefault
pageNoPage to start from (pages hold 500 rows, the smallest page size the API allows)
job_idNoRecords relating to this job (API `jobId`)
form_idYesForm ID (a positive whole number)
max_pagesNoPages of 500 to fetch in this call
created_toNoRecords created on or before this (API `createdDateTo`). A date alone means 23:59:59 UTC.
user_groupNoRecords from users in this user group (API `userGroup`)
max_resultsNoMost rows to return; rows beyond this on pages already fetched are counted, not returned
uploaded_toNoRecords uploaded on or before this (API `uploadedDateTo`)
created_fromNoRecords created on or after this (API `createdDateFrom`). A date alone means 00:00:00 UTC.
newest_firstNoOrder by record Id, newest first (the documented orderBy example) or oldest first
field_filtersNoUser-defined field filters (API `userDefinedFilter`). Different fields are ANDed; the same field given twice is ORed.
uploaded_fromNoRecords uploaded from the device on or after this (API `uploadedDateFrom`)
mobile_user_idNoRecords collected by this mobile user (API `mobileUserId`)
include_contact_detailsNoInclude personal answers and links to media (never downloaded), and stop redacting emails, phone numbers, postcodes and coordinates in other answers. Off by default. Bank, card and payment details are never returned.

TDQS

A4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Adds substantial behavior beyond the annotations: it details the default PII redaction rules (which field categories are withheld, which values are redacted, and the free-text gaps), states that media links are never downloaded even when include_contact_details is set, notes bank/card/payment details are never returned, and discloses that pages hold 500 records. That is exactly the kind of operational context annotations cannot carry.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four sentences, each carrying load: search scope, return shape, redaction behavior, and read/POST/paging semantics. It is front-loaded with the endpoint and purpose. The redaction sentence is long and parenthetical-heavy, slightly taxing to parse, which keeps it below a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 14-parameter search tool with no output schema, the description compensates well: it sketches the returned record (Id, OriginalId, JobId, system columns, answers), states page size and paging intent, and covers the privacy-affecting default. An agent has everything needed to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so every parameter is already documented in structured data, which sets the baseline at 3. The description clarifies the practical consequence of include_contact_details (what is unredacted and what remains withheld), but otherwise adds little parameter-level detail beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource ('Search the records submitted on one form'), scopes it to a single form, and lists the searchable dimensions (dates, job, mobile user, user group, field values). It does not name the sibling get_form_submission or explain how it differs, so it stops short of full sibling differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied clearly: call this to search/filter records across a form, and the enumerated filter dimensions tell the agent what queries are possible. However, there is no explicit when-not guidance and no routing to the obvious alternative (get_form_submission for a single record), leaving the agent to infer the boundary.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_jobsSearch jobsA
Read-onlyIdempotent

Search jobs with the filters POST /api/jobs/search documents: status IDs, estimated start date range, the mobile users they are allocated to, job types, a description, priority, backlog and whether a duration is set. Returns job ID, description, status ID, type, priority, dates and allocation; the job's location is withheld unless include_contact_details is set. In descriptions, emails, phone numbers, postcodes and coordinates are redacted, but names and street addresses typed into them are not. This search is a POST request that only reads. Pages hold 500 jobs; a page with fewer than 500 is the last.

ParametersJSON Schema
NameRequiredDescriptionDefault
pageNoPage to start from (pages hold 500 rows, the smallest page size the API allows)
backlogNoOnly backlog jobs (true) or only non-backlog jobs (false) (API `backlog`)
priorityNoOnly jobs with this priority (API `priority`)
max_pagesNoPages of 500 to fetch in this call
status_idsNoOnly jobs with these status IDs (API field `jobStatusId`); decode them with list_job_statuses. WorkMobile's own example uses [1,2,3,5] for jobs that are not closed.
descriptionNoJobs matching this description (API `description`)
max_resultsNoMost rows to return; rows beyond this on pages already fetched are counted, not returned
has_durationNoOnly jobs with a duration set (API `hasDuration`)
job_type_idsNoOnly jobs of these types (API `jobTypeIds`)
mobile_user_idsNoOnly jobs allocated to these mobile users (API `allocatedToUserId`)
estimated_start_toNoJobs estimated to start on or before this (API `estimatedStartDateTimeTo`). A date alone means 23:59:59 UTC that day.
estimated_start_fromNoJobs estimated to start on or after this (API `estimatedStartDateTimeFrom`). A date alone means 00:00:00 UTC that day.
include_contact_detailsNoInclude the job location (address), and stop redacting emails, phone numbers, postcodes and coordinates in descriptions and names. Off by default. Bank, card and payment details are never returned.
order_by_estimated_startNoSort by estimated start (API orderBy on `estimatedStartDateTimeFrom`, as in WorkMobile's example)

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark it readOnly/idempotent/non-destructive, and the description still adds substantial context: it explains the POST-but-reads-only quirk, the 500-row page size and last-page detection rule, and the precise redaction policy (emails/phones/postcodes/coordinates redacted, names/street addresses not). It also notes the location is withheld unless include_contact_details is set.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A dense, front-loaded paragraph that leads with the search filters, then return shape, then pagination. Most sentences earn their place, though the filter list is somewhat redundant with the schema and could be trimmed.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the return-value burden and does so ('job ID, description, status ID, type, priority, dates and allocation'), and adds pagination and privacy semantics. An agent has everything needed to call and interpret results.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so each parameter is already fully documented with API field mappings. The description's filter enumeration largely mirrors the schema rather than adding syntax or edge-case detail beyond it, so the baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Search jobs'), names the underlying endpoint, and enumerates exactly what can be filtered on. It is trivially distinguishable from siblings like get_job (single fetch) or list_job_statuses (lookup).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear operational context and routes the agent to list_job_statuses for decoding status IDs, which is a genuinely useful dependency hint. It does not, however, state when NOT to use this tool versus get_job for single-record retrieval, so it falls short of the explicit when/when-not bar.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_job_statusesList job statusesA
Read-onlyIdempotent

WorkMobile's static list of job statuses and their IDs (GET /api/jobs/jobstatuslist), to decode job_status_id and to pick status_ids for list_jobs. The response format is not documented, so it is returned as WorkMobile sends it.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, openWorldHint and destructiveHint=false, so the safety profile is covered. The description adds genuinely new context: the data is static and the response format is undocumented and returned verbatim, warning the agent not to assume a schema. It doesn't say anything about caching or ID stability, keeping it out of the 5 band.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, both earning their place: the first states purpose, endpoint, and use case; the second flags the undocumented response. Front-loaded and waste-free.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no parameters and no output schema, the description carries the burden and does so well by naming the endpoint and warning that the response shape is undocumented. Minor remaining gap: it could hint at the rough shape (list of id/name pairs) or whether the list is stable enough to cache, but nothing essential is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so the baseline is 4. There is nothing for the description to clarify about inputs, and it correctly does not pad with irrelevant parameter talk.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("static list of job statuses and their IDs") plus the backing endpoint GET /api/jobs/jobstatuslist. It also names two concrete downstream uses (decode job_status_id, pick status_ids for list_jobs), which distinguishes it from siblings like list_job_types and list_jobs.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear context for when to call it: to decode a job_status_id or to select status_ids to pass into list_jobs, explicitly naming that sibling. It stops short of stating when NOT to use it (e.g., if you already have the decoded labels cached), so it falls just short of the top band.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_job_typesList job typesB
Read-onlyIdempotent

Job types available to the API user (GET /api/jobtypes): ID, name, description, whether live, the form each uses, default duration and location settings.

ParametersJSON Schema
NameRequiredDescriptionDefault
include_inactiveNoInclude job types that are not live

TDQS

B3.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, openWorld and non-destructive, so the safety profile is covered without the description. The description adds the shape of returned records and the underlying endpoint, but says nothing about pagination, volume, or ordering for what could be a long list.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

One compact sentence that front-loads the resource and endpoint, then enumerates the returned fields. No filler, though the field enumeration makes it slightly dense.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, enumerating the returned fields (ID, name, description, live flag, form, duration and location defaults) is genuinely useful compensation. A simple read-only listing tool is otherwise complete, with only pagination details missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the single parameter (include_inactive) is fully documented in the schema with its default. The description's mention of 'whether live' overlaps with that concept but adds no new syntax or filtering semantics, so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (list) and resource (job types), plus the endpoint and the fields each record contains, so the agent knows exactly what comes back. It does not explicitly differentiate itself from siblings like get_job_type or list_job_statuses, which keeps it below a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no guidance on when to use this versus get_job_type (single lookup) or list_job_statuses. Usage is only implied by the verb 'List' and the scoping phrase 'available to the API user'.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_mobile_usersList mobile usersA
Read-onlyIdempotent

Mobile (field) users visible to the API user (GET /api/mobileusers) with their names, job titles, user group (named from GET /api/usergroups) and whether active. Usernames only with include_contact_details. The API returns the whole list without paging.

ParametersJSON Schema
NameRequiredDescriptionDefault
user_group_idNoOnly users in this user group
include_inactiveNoInclude inactive users
include_contact_detailsNoInclude usernames (often email addresses), and stop redacting emails and phone numbers typed into names and job titles. Off by default. Bank, card and payment details are never returned.

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive and openWorld, so the safety profile is covered. The description nonetheless adds real behavioral detail: the list is never paged, user groups are resolved by name from GET /api/usergroups, and contact details are redacted unless include_contact_details is set.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three dense sentences with the resource and scope front-loaded and no filler. Minor overlap between the description's contact-detail clause and the schema's own explanation keeps it from a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the return-shape burden and lists the fields returned plus the no-paging caveat, which is adequate for a read-only list tool. It stops short of describing ordering or size limits of that whole-list response.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the schema parameter descriptions are already detailed (including the redaction behavior and the bank/card exclusion). The description only lightly restates include_contact_details behavior, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource ('Mobile (field) users visible to the API user'), pins it to an endpoint (GET /api/mobileusers), and enumerates the returned fields (names, job titles, user group, active flag). It is unmistakably distinct from the job/form/approval listing siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear context ('visible to the API user') and notes the no-paging behavior, but never states when to reach for this tool versus another or any prerequisite. No sibling competes directly, so the omission is mild rather than harmful.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 10 tool updatesv0.1.0
    • First observedget_form_submission
    • First observedget_job
    • First observedget_job_type
    • First observedlist_approvals
    • First observedlist_form_submissions
    • First observedlist_forms
    • First observedlist_job_statuses
    • First observedlist_job_types
    • First observedlist_jobs
    • First observedlist_mobile_users

TDQS

A3.9/5.0

Scored across 10 tools

Disambiguation4/5

Most tools target a distinct resource+action (statuses, types, forms, submissions, jobs, users), and search vs. single-get pairs are clearly separated. Minor overlap comes from list_approvals behaving differently depending on whether form_id is passed, which adds a bit of cognitive load.

Naming Consistency5/5

Names follow a strict and predictable verb_noun pattern: list_* for collections (list_jobs, list_forms, list_mobile_users) and get_* for single items (get_job, get_job_type, get_form_submission). The convention is applied uniformly across all ten tools.

Tool Count5/5

Ten tools is well within the ideal range and each one maps to a meaningful read operation over the WorkMobile domain. Nothing appears redundant or padded.

Completeness3/5

The read surface is reasonably broad (lookups, searches, single-item gets for jobs, forms, submissions, users, approvals), but it is entirely read-only with no create/update operations. get_job_type explicitly says 'Call this before create_job,' yet no create_job tool exists, indicating a notable gap.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

  • Give AI assistants secure access to your organization's structured business data. Search records, create and update records, retrieve schema information, and manage workflow states using natural language. You need two values for every request: x-api-key — your Web Data Forms API Key x-group-id — your Web Data Forms Group ID You can find these in your Web Data Forms accounts group->information page. Preferred method: request header When possible, pass the credentials as HTTP headers: x-api-key: <your-api-key> x-group-id: <your-group-id> This is the preferred option because it keeps credentials out of the URL and is more secure. Fallback method: query parameters If your MCP client does not support custom headers, the server also accepts the credentials as URL query parameters. Example: https://mcp.webdataforms.com?x-api-key=abc123&x-group-id=xyz456 Detailed information here: https://github.com/Web-Data-Forms/mcp-server-docs/blob/main/README.md

  • Let AI agents query data and act across all your business apps via MCP.

  • MCP server that lets AI assistants use all OneSchema features exposed via the public API.

  • Discover, plan and run tools across your connected business systems through one OAuth MCP endpoint

Related MCP Servers

  • A
    license
    A
    quality
    B
    maintenance
    Enables AI assistants to read and manage a Jobkeepr field service business including jobs, customers, scheduling, estimates, invoices, and payments via MCP.
    19
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    Enables Claude, ChatGPT and other MCP clients to read an Amiqus ID account—clients, onboarding records and steps, check results, templates, case status counts and webhooks—and, when writes are enabled, create records.
    9
    MIT
  • A
    license
    B
    quality
    C
    maintenance
    Enables Claude, ChatGPT and other MCP clients to read practice-management data including organization, clinicians, diaries, availability, bookings, patients, invoices, payments, staff tasks, services, and locations, and optionally create staff tasks, create bookings, and cancel bookings.
    15
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Lets MCP clients such as Claude and ChatGPT read a rota and time-and-attendance account, exposing venues, groups, shifts, absences and absence types, time entries, venue events and staff names through read-only tools that never return pay data.
    MIT