WorkMobile MCP server
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@WorkMobile MCP serverWhat's waiting for my approval on the Customer Visit Record form?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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 |
| 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. |
|
| One job: description, status, type, priority, dates, allocation, history (status changes with narrative) and job data. |
|
| WorkMobile's static list of job status IDs, returned as WorkMobile sends it (the format is not documented). |
|
| Job types with the form each uses, default duration and location settings. |
|
| One job type and the fields a job of that type takes (name, type, required, allowed values, limits), read from its JSON Schema document. |
|
| Forms visible to the API user (sub-forms hidden unless asked). The API returns the whole list without paging. |
|
| 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. |
|
| One record by its Id (the search's |
|
| Without |
|
| Field staff with name, job title, user group name and whether active (inactive users hidden unless asked). |
|
| 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. |
|
| Allocates or reallocates a job to one mobile user, replacing any previous allocation. Marked destructive. Writes only. |
|
| Approves the current approval step of a record as the API user. Cannot be undone. Marked destructive. Writes only. |
|
| Rejects a record's current approval step. Rejection is terminal: the workflow stops for good. Marked destructive. Writes only. |
|
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 buildYou 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.jsVariable | Required | Meaning |
| yes | The API token (a GUID) of a portal user, sent as the |
| no |
|
| no | Defaults to |
Safety defaults
Read-only unless
WORKMOBILE_ALLOW_WRITES=true. Every read tool carries the MCPreadOnlyHintannotation, including the ones that call a search endpoint withPOST(list_jobs,list_form_submissions,get_form_submission, andlist_approvalswith aform_id): WorkMobile runs its job and record searches asPOSTrequests with a criteria body, and they change nothing.allocate_job(it replaces the job's current allocation),approve_recordandreject_record(they move an approval workflow on for good) carrydestructiveHint: true, since MCP reservesfalsefor 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'sUsername(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+or00, UK numbers with a bracketed area code, and UK-style0…numbers of 9 to 11 digits; other digit strings starting with0are 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…orwww.…) 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,
CreatedByon records and job history, and the approval columns of a record. A record'sCustomercolumn, like any field with "customer" in its name, is withheld. A system column (such asCreatedByorUserGroup) or a jobLocationthat 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 (adata: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
FormIdin the path of the records search, which it types as a string; form IDs are int32 everywhere else). Dates takeYYYY-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 (Zor 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
GETonly; when all three attempts fail the error says the service may be unavailable, without the gateway's HTML. NoPOSTis 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_joborlist_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-recordGETanswering 200 withnullor 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,detailand fielderrorswhen 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 testThe 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 withadditionalProperties: false) and its multipart schema forPOST /api/jobs. One substitution: the spec'sUserDefinedFieldFilteris an object with no properties andadditionalProperties: false, so it accepts only{}and would reject every documented filter example; filter items are validated against the spec'sUserDefinedFieldFilterDefinition(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/Formsexample shows"LastUpload": nullwhere 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.mjsholds a schema written by hand from what is documented (the numericId,OriginalIdandJobIdcolumns the search documentation filters and sorts on, and theCreatedandCreatedBystatic 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 documentedGET /api/Formsexamples 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):
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 withoutOriginalId, 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.Starts a local mock of the API under
/webapi2that requires theX-API-Keyheader (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 documentedpaginationbody (refusing arowCountbelow 500, and a record search withoutorderBy, 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 firstGET /api/formswith a 429. The mock's list and detail responses are validated against the schemas above.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 (inlist_jobs,get_job,list_form_submissions,get_form_submission,list_approvalswith aform_id,list_mobile_users,list_formsand the approval inbox totals: personal fields by name, includingDoB,D.O.B,NINumber,What3WordsandMob No, a bare link, emails, phone numbers, postcodes and coordinates in text) and its return on request (inget_job,get_form_submission,list_approvalsandlist_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 objectLocationredacted like job data; a double-encoded job type schema (read byget_job_typeand used bycreate_job) and job search answer decoded; the write tools absent withWORKMOBILE_ALLOW_WRITESunset and set tofalse;create_jobposting a multipart form whose fields are all in the spec's schema and validate against it, withDataas{"jobData": …}, and refusing unknown fields, missing required fields, disallowed values, text for a numeric field and half a location before anyPOST;allocate_job,approve_recordandreject_recordbodies 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 200nullor{}job read as not found; requests of a paged search spaced by the 250 ms throttle, and paging stopping oncemax_resultsrows are in hand; the 429 retry waiting forRetry-Afterin the seconds, fractional-seconds and HTTP-date forms and the 2 s fallback when the header is absent, retrying aPOSTwith the same body (page 2 of a three-page search asked for again with no row lost or duplicated, and a rate-limitedPOST /api/jobscreating exactly one job), giving up after three attempts on a persistent 429 and at once on aRetry-Afterabove the cap; a 502 retried for aGETand never for aPOSTsearch or write, with the right advice in each case; three 503s on aGETreported 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 carriedX-API-Key(the configured one, except the deliberate wrong-key call) and noAuthorizationheader, 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/searchandPOST /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 asGET /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,OriginalIdandJobIdare 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 howuserDefinedFilteritems are really read, given the spec's emptyUserDefinedFieldFilterschema.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}/schemareturns 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'sLocationis 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
nullor{}.The format of
GET /api/jobs/jobstatuslistandGET /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: thatDatais the JSON document{"jobData": {…}}(the documented JSON Schema describes an object with ajobDataproperty), thatAllocatedMobileUserIdandAllocatedUserGroupIdof0mean unallocated (as the connector says), whatPriorityvalues andDurationunit are valid, thatEstimatedStartaccepts 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 arequiredarray 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),approveandreject(documented only as "Success"), and whatapprove/rejectanswer for a record with no step pending for the API user.Whether a 429 on a
POSTmeans 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 toolsget_form_submissionGet a submitted form recordARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| form_id | Yes | Form ID (a positive whole number) | |
| record_id | Yes | Record ID (a positive whole number) | |
| include_contact_details | No | Include 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
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.
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.
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.
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.
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.
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 jobARead-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}.
| Name | Required | Description | Default |
|---|---|---|---|
| job_id | Yes | Job ID (a positive whole number) | |
| include_contact_details | No | Include 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
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.
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.
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.
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.
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.
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 typeARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| job_type_id | Yes | Job type ID (a positive whole number) |
TDQS
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.
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.
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.
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.
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.
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 approvalsARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page to start from (pages hold 500 rows, the smallest page size the API allows) | |
| form_id | No | List the records on this form that are pending the API user's approval | |
| max_pages | No | Pages of 500 to fetch in this call | |
| max_results | No | Most rows to return; rows beyond this on pages already fetched are counted, not returned | |
| include_contact_details | No | Include personal answers in the pending records. Off by default. Bank, card and payment details are never returned. |
TDQS
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.
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.
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.
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.
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.
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 formsARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| live_only | No | Only live forms | |
| include_subforms | No | Include sub-forms |
TDQS
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.
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.
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.
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.
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.
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 recordsARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page to start from (pages hold 500 rows, the smallest page size the API allows) | |
| job_id | No | Records relating to this job (API `jobId`) | |
| form_id | Yes | Form ID (a positive whole number) | |
| max_pages | No | Pages of 500 to fetch in this call | |
| created_to | No | Records created on or before this (API `createdDateTo`). A date alone means 23:59:59 UTC. | |
| user_group | No | Records from users in this user group (API `userGroup`) | |
| max_results | No | Most rows to return; rows beyond this on pages already fetched are counted, not returned | |
| uploaded_to | No | Records uploaded on or before this (API `uploadedDateTo`) | |
| created_from | No | Records created on or after this (API `createdDateFrom`). A date alone means 00:00:00 UTC. | |
| newest_first | No | Order by record Id, newest first (the documented orderBy example) or oldest first | |
| field_filters | No | User-defined field filters (API `userDefinedFilter`). Different fields are ANDed; the same field given twice is ORed. | |
| uploaded_from | No | Records uploaded from the device on or after this (API `uploadedDateFrom`) | |
| mobile_user_id | No | Records collected by this mobile user (API `mobileUserId`) | |
| include_contact_details | No | Include 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
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.
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.
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.
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.
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.
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 jobsARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page to start from (pages hold 500 rows, the smallest page size the API allows) | |
| backlog | No | Only backlog jobs (true) or only non-backlog jobs (false) (API `backlog`) | |
| priority | No | Only jobs with this priority (API `priority`) | |
| max_pages | No | Pages of 500 to fetch in this call | |
| status_ids | No | Only 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. | |
| description | No | Jobs matching this description (API `description`) | |
| max_results | No | Most rows to return; rows beyond this on pages already fetched are counted, not returned | |
| has_duration | No | Only jobs with a duration set (API `hasDuration`) | |
| job_type_ids | No | Only jobs of these types (API `jobTypeIds`) | |
| mobile_user_ids | No | Only jobs allocated to these mobile users (API `allocatedToUserId`) | |
| estimated_start_to | No | Jobs estimated to start on or before this (API `estimatedStartDateTimeTo`). A date alone means 23:59:59 UTC that day. | |
| estimated_start_from | No | Jobs estimated to start on or after this (API `estimatedStartDateTimeFrom`). A date alone means 00:00:00 UTC that day. | |
| include_contact_details | No | Include 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_start | No | Sort by estimated start (API orderBy on `estimatedStartDateTimeFrom`, as in WorkMobile's example) |
TDQS
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.
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.
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.
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.
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.
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 statusesARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
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.
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.
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.
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.
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.
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 typesBRead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| include_inactive | No | Include job types that are not live |
TDQS
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.
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.
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.
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.
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.
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 usersARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| user_group_id | No | Only users in this user group | |
| include_inactive | No | Include inactive users | |
| include_contact_details | No | Include 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
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.
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.
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.
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.
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.
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.
10 tool updates
v0.1.0- First observed
get_form_submission - First observed
get_job - First observed
get_job_type - First observed
list_approvals - First observed
list_form_submissions - First observed
list_forms - First observed
list_job_statuses - First observed
list_job_types - First observed
list_jobs - First observed
list_mobile_users
TDQS
Scored across 10 tools
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.
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.
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.
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
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
- AlicenseAqualityBmaintenanceEnables AI assistants to read and manage a Jobkeepr field service business including jobs, customers, scheduling, estimates, invoices, and payments via MCP.19MIT
- AlicenseAqualityCmaintenanceEnables 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.9MIT
- AlicenseBqualityCmaintenanceEnables 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.15MIT
- AlicenseNot gradedqualityCmaintenanceLets 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