Synthire
Click on "Install 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., "@SynthireHire a new worker with the same job as Liz Erd."
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.
Synthire: MCP server for synthetic Workday test data generation
Chat: "Hire a new worker with the same job as Liz Erd." Synthire searches Workday for the template worker, confirms the match with you, clones the job/org context, generates a fresh synthetic identity, and submits a real Workday Hire_Employee API call. All with you approving the exact details before anything is sent.
Why this project exists
I build and test Workday integrations for a living, and entering test data transactions by hand is one of the more boring and repetetive parts o the job. Hiring a single worker means assembling several interdependent fields (Supervisory Organization, Job Profile, legal name, contact info) and approval steps that are more than tedious. This project automates that specific pain point, and doubled as a way to learn about the Model Context Protocol hands-on rather than just read about it.
What this demonstrates
MCP server design, not just API wrapping: four small, single-purpose tools (
search_workers,get_worker_template,generate_synthetic_identity,synthesize_test_hire) instead of one do-everything tool, so the orchestrating agent (and a human) can inspect and intervene between each step.Human-in-the-loop safety design for a mutating action. The agent is explicitly instructed (see Agents.md) to disambiguate the template worker and get sign-off on the exact hire payload before the one tool that actually writes data. This mirrors how you'd actually want an agent to behave against a real Workday tenant.
Building a safe environment to demo an inherently risky workflow. "Let an LLM hire people in Workday" isn't something you point at a production or even a real sandbox tenant on day one. A FastAPI mock tenant makes the whole flow demoable with real XML API calls and testable without compromising real HR data (nor my career).
Realistic API mocking, not a JSON toy stand-in. The mock tenant speaks actual Workday SOAP envelopes (
urn:com.workday/bsvcnamespace,v45.0-style versioning,Applicant_Data/Legal_Name_Data/Organization_Referenceelement names) built withxml.etree.ElementTree, and a single SOAP endpoint that dispatches on the wrapped request element the same way Workday's real endpoint does.Workday domain knowledge. Workday API's define dozens of optional sections for (benefits, national IDs, military service...). Rather than guess at what's "required," a smalls cript walked the raw XSD to find real
minOccurs="1"constraints, and separately mined thewd:Validationannotations embedded in the WSDL for business-rule requirements the schema itself doesn't enforce (e.g. "The Hire Date is required", "A legal name is required when adding an applicant").
Related MCP server: Customer Health Intelligence MCP Server
Architecture
Two independent local processes talking real (simplified) Workday SOAP + RaaS-style REST over HTTP — no Workday authentication involved, by design, since this is a local prototype, not a path to a live tenant:
Claude Desktop (or any MCP client)
│ stdio (MCP)
▼
MCP Server (src/synthire/mcp_server/)
│ HTTP (RaaS REST + SOAP/XML)
▼
Mock FastAPI Tenant (src/synthire/mock_tenant/)
│
▼
devdata/worker_list.csv (seed data)MCP Server (
src/synthire/mcp_server/) — built with the officialmcpSDK (MCPServer, the current v2.x API). Exposes four tools to an MCP client:search_workers(name)— find template worker candidatesget_worker_template(employee_id)— fetch the confirmed template's cloneable fields via Workday'sGet_WorkersAPIgenerate_synthetic_identity(country)—Faker-generated name/email, locale-matched to the template's countrysynthesize_test_hire(...)— submits the user-approved payload via Workday'sHire_EmployeeAPI
Mock Tenant (
src/synthire/mock_tenant/) — a FastAPI app standing in for a Workday tenant.GET /ccx/api/v1/tenant/search_workers?name=...— RaaS-style report backed bydevdata/worker_list.csvPOST /ccx/service/tenant/Staffing/v45.0— one SOAP endpoint dispatchingGet_WorkersandHire_Employeeby sniffing the request body for the wrapped element nameIn-memory state (
state.py) seeded from the CSV; a successful hire is validated Workday-style and immediately visible to a follow-upGet_Workerscall; a failed one comes back with real-soundingExceptions_Datamessages
Shared modules (workday_xml.py, models.py, config.py) keep SOAP envelope building/parsing and field definitions in one place, so the mock tenant and the MCP client can never drift out of agreement on the wire format.
Why only required fields?
Implementing exactly the schema-required + business-rule-required subset — legal name, one contact method, a Supervisory Organization, a Hire Date, and a Job Profile — keeps the prototype's surface area small without faking the shape of the real integration. Every element name and namespace in the generated XML is authentic Workday. What's been trimmed is the volume of optional data, not fidelity. This sets up a solid base for extending in the future..
Logging
Processes log through Python's standard logging module, configured once in config.configure_logging() with a consistent HH:MM:SS [logger.name] LEVEL: message format. Logs deliberately go to stderr, not stdout: the MCP server talks to its client over stdio, and stdout is reserved for the JSON-RPC protocol stream — writing logs there would corrupt the connection.
The mock tenant (
mock_tenant/app.py,mock_tenant/state.py) logs every RaaS search, every SOAP dispatch, and every hire attempt — including why a hire was rejected (the same validation messages returned to the caller).The MCP server (
mcp_server/server.py) logs every tool call's key inputs and outcome, so a debugging session can see exactly what the agent decided to call and with what arguments, independent of what the chat transcript shows.
This is enough to debug a single run; it doesn't persist anywhere. See Ideas for Future Development for a durable audit trail.
Prerequisites
Python 3.13+
uvpackage managerClaude Desktop (or another MCP client)
Quickstart
Install dependencies:
uv syncStart the mock Workday tenant (in one terminal):
uv run synthire-mockPoint an MCP client at the server. For Claude Desktop, add to
claude_desktop_config.json:{ "mcpServers": { "synthire": { "command": "uv", "args": [ "run", "--directory", "/absolute/path/to/synthire", "synthire-mcp" ] } } }Or run it standalone for debugging:
uv run synthire-mcpChat: "I want to hire a new worker with the same job as Scott Peterson." (See
devdata/worker_list.csvfor other names in the seed data.)
Project Layout
devdata/ # WSDLs, sample SOAP payloads, and the worker CSV fixture
src/synthire/
config.py # shared namespace/version/paths + logging setup
models.py # WorkerCandidate, WorkerTemplate, HireProposal, HireResult
workday_xml.py # build/parse Get_Workers + Hire_Employee SOAP envelopes
csv_store.py # loads devdata/worker_list.csv
mock_tenant/
app.py # FastAPI app (RaaS search + SOAP dispatch)
state.py # in-memory tenant state + hire validation
mcp_server/
client.py # WorkdayClient (HTTP calls to the mock tenant)
server.py # MCP tool definitionsIdeas for Future Development
The near-term punch list (tests, error handling, config cleanup) lives in plan.md. These are the bigger, longer-term directions this could grow in:
Testing & reliability
An automated test suite (
pytest) forworkday_xmlbuild/parse round-trips andTenantStatevalidation — everything so far has been verified by hand.CI (GitHub Actions) running lint + tests on push once that suite exists.
Observability
A durable audit trail of every synthetic hire attempted (not just logged to stderr) — a small append-only store (SQLite or a JSONL file) recording who/what/when for each
Hire_Employeecall, surviving a mock-tenant restart. Today's logging (see above) is enough to debug one run, but there's no record once the process exits, and no way to answer "what test data has this tool ever created" after the fact — which matters once synthetic workers need to be tracked and cleaned up in a shared sandbox.Structured (JSON) log output as an option, so logs could feed a real log aggregator once this points at anything other than a local mock.
Real Workday connectivity
OAuth 2.0 / Integration System User (ISU) authentication, so the MCP server can talk to an actual Workday tenant instead of only the mock — the biggest step from "prototype" to "usable tool."
Support for multiple test environments (e.g. different sandbox tenants per team or per release), with the MCP server selecting or being told which tenant to target rather than hardcoding one base URL.
Once real connectivity exists: guardrails specific to that risk — e.g. refusing to run against anything that doesn't look like a sandbox/non-prod tenant URL, and a hard cap on hires per session.
Tagging synthetic workers distinctly (a naming convention or custom ID field) so test data stays identifiable and easy to clean up in a shared real sandbox, rather than blending in with real employees.
A companion "terminate" tool to clean up synthetic workers after a test run —
Staffing.wsdlalready definesTerminate_Employee, so this would follow the same pattern asHire_Employee.
More flexible input
Accepting criteria beyond a template worker's name — e.g. "I need an Australian Sales worker" — by adding a filtered search tool (country, job family, job profile, manager flag) alongside the name-based
search_workers, so the agent can pick or synthesize a template from criteria instead of requiring a specific person to clone.Batch generation — "hire 5 test workers across different countries" — for teams that need a population of test data rather than one worker at a time.
Extending beyond
Hire_Employeeto other Staffing business processes already defined in the WSDL (Edit_Position,Change_Job, contingent worker hires), generalizing this from a hire-only tool into a broader test-data operations server.
Fidelity & scope
Progressively adding optional
Hire_Employeesections (compensation package, position time type, employee type) as deliberate, individually-justified extensions rather than all at once — each one earning its place the same way the current required-field set did.A "dry run" mode that shows the exact generated SOAP envelope before submission, for advanced users who want to inspect the wire format directly.
Persisting mock tenant state (SQLite instead of in-memory) so longer demo sessions or repeated test runs survive a restart.
See plan.md for a full breakdown of work completed and what's still open, and Agents.md for the exact human-in-the-loop instructions the agent follows.
Available Tools
4 toolsgenerate_synthetic_identityA
Generate a fresh synthetic first name, last name, and email.
Use this to give the new hire its own identity instead of literally
duplicating the template worker's name. country should be an
ISO 3166-1 alpha-3 code (e.g. "USA", "GBR", "JPN") -- it's used to pick a
locale-appropriate name where supported, falling back to en_US otherwise.
| Name | Required | Description | Default |
|---|---|---|---|
| country | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. It does disclose locale resolution behavior ('locale-appropriate name where supported, falling back to en_US'), which is genuinely useful, but says nothing about randomness, uniqueness guarantees, persistence, or whether re-invocation produces different values.
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-loaded with the output, then usage rationale, then parameter semantics in a logical progression. Slightly verbose in the 'literally duplicating the template worker's name' clause, but no sentence 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 one param, no annotations, and no output schema, the description covers purpose, usage context, the single parameter, and names the generated fields. It could state the return shape (single object vs separate values), but it is otherwise complete for a simple generator.
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 0%, so the description must compensate, and it does fully: it specifies the exact format (ISO 3166-1 alpha-3), gives concrete examples ('USA', 'GBR', 'JPN'), and explains the parameter's effect (locale-based name selection with en_US fallback). This adds far more than the bare 'Country' string field.
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 (generate) and precise resource (synthetic first name, last name, email). It implicitly distinguishes itself from get_worker_template by explaining it avoids 'literally duplicating the template worker's name,' but does not name or contrast with the sibling tools directly.
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 a clear when-to-use scenario: 'give the new hire its own identity instead of literally duplicating the template worker's name,' anchoring it in the hire-synthesis workflow. No explicit when-not or named alternative (e.g. synthesize_test_hire) is provided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_worker_templateA
Fetch the confirmed template worker's cloneable fields via Get_Workers.
Call this only after the user has confirmed exactly which worker (by employee_id) to use as the template -- it returns the job profile, supervisory org, and country that a new hire will be cloned from.
| Name | Required | Description | Default |
|---|---|---|---|
| employee_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description must carry the behavioral burden. It discloses that the tool returns cloneable fields (job profile, supervisory org, country) and requires prior user confirmation, which is useful. However, it does not specify permission requirements, whether the operation is read-only, or any rate limits, leaving significant behavioral gaps for a tool with zero annotation coverage.
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?
The description is concise, front-loading the core action in the first sentence and then the usage condition in the second. Both sentences earn their place, though the parenthetical explanation could be slightly tighter.
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 single-parameter tool with no output schema and no annotations, the description covers the purpose and usage condition but lacks behavioral details such as read-only nature, permissions, and error handling. It is adequate but not fully complete given the lack of structured metadata.
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?
With 0% schema description coverage and one required parameter, the description implies that employee_id identifies the confirmed template worker but does not add format, syntax, or source details beyond what the schema name suggests. It partially compensates by linking the parameter to the confirmation step, but not enough to fully document it.
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 clearly states a specific verb and resource: fetching a confirmed template worker's cloneable fields via Get_Workers, and enumerates what is returned (job profile, supervisory org, country). It distinguishes the purpose from siblings like search_workers by emphasizing the confirmed template selection, though it does not name a direct sibling as an alternative.
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?
Explicitly states when to use it: 'Call this only after the user has confirmed exactly which worker (by employee_id) to use as the template.' This provides a clear prerequisite and timing condition, effectively guiding the agent on when and when not to invoke the tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_workersB
Search the Workday worker population by name to find a template worker.
Returns candidate matches (employee_id, name, job_profile, country) for the user to disambiguate between if more than one comes back.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It does disclose the returned fields and the multi-match disambiguation behavior, which is genuinely useful, but says nothing about match semantics (exact vs partial, case sensitivity), empty-result behavior, or read-only nature beyond the word 'search'.
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 tight sentences with the primary action front-loaded and the return behavior appended. Every sentence contributes, though the return-field listing is somewhat redundant given an output schema exists.
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?
The presence of an output schema lowers the bar for explaining return values, and the description covers the disambiguation case. However, for a search tool it omits essential call-correctness details like matching semantics and empty-result handling, leaving a noticeable gap.
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?
Only one parameter at 0% schema description coverage, so the description must compensate. 'By name' restates the parameter name without clarifying expected format (full name, partial, surname-only) or matching behavior, adding little beyond what the schema's field title conveys.
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 the Workday worker population by name') and ties it to a downstream goal ('find a template worker'), which distinguishes it from synthesize_test_hire and generate_synthetic_identity. It does not explicitly contrast with get_worker_template, which is the nearest sibling, so it falls short of 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 phrase 'find a template worker' implies this is a lookup step preceding get_worker_template, but no when-to-use, prerequisites, or explicit alternative is named. Usage is left to inference rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
synthesize_test_hireA
Submit the user-approved hire payload to the tenant via Hire_Employee.
Only call this after the user has explicitly confirmed the proposed
fields -- this is the one tool in this server that actually mutates the
tenant. country is an ISO 3166-1 alpha-3 code; hire_date defaults to
today (ISO format) if omitted. employee_id is optional -- leave it out
to let the tenant auto-assign one.
| Name | Required | Description | Default |
|---|---|---|---|
| Yes | |||
| country | Yes | ||
| hire_date | No | ||
| last_name | Yes | ||
| first_name | Yes | ||
| employee_id | No | ||
| job_profile | Yes | ||
| position_id | No | ||
| supervisory_org | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses the mutation, the mandatory user-confirmation gate, and that Hire_Employee is the underlying mechanism. It omits permissions/scopes required, reversibility or undo behavior, and failure semantics, leaving real gaps for a destructive operation.
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 action and the critical safety gate in the first sentence, then handles parameter clarifications in compact clauses. Every sentence earns its place with no repetition of the schema.
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 9-parameter mutating tool with no annotations and no output schema, the description nails the behavioral essentials (mutation + confirmation) but leaves the majority of parameters undocumented and says nothing about results, errors, or permissions. Adequate but with clear gaps.
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 0% and there are 9 parameters, so the description must compensate. It documents only three: country as an ISO 3166-1 alpha-3 code, hire_date defaulting to today in ISO format, and employee_id as optional/auto-assigned. job_profile, supervisory_org, position_id, email, first_name, and last_name remain entirely undefined.
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 ('Submit the user-approved hire payload to the tenant via Hire_Employee') and explicitly positions itself against siblings by noting it is 'the one tool in this server that actually mutates the tenant', distinguishing it from search_workers, get_worker_template, and generate_synthetic_identity.
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 a clear precondition ('Only call this after the user has explicitly confirmed the proposed fields'), which is strong usage guidance for an irreversible action. It does not name an alternative tool or describe a when-not-to-use path beyond that gate, so it stops short of a 5.
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.
4 tool updates
v0.1.0- First observed
generate_synthetic_identity - First observed
get_worker_template - First observed
search_workers - First observed
synthesize_test_hire
TDQS
Scored across 4 tools
Each tool occupies a distinct stage of a clear pipeline: search candidates, fetch a confirmed template's cloneable fields, generate a synthetic identity, and submit the hire payload. The descriptions explicitly note sequencing ('call this only after...'), leaving no overlap between them.
All four tools follow a consistent snake_case verb_noun convention (search_workers, get_worker_template, synthesize_test_hire, generate_synthetic_identity). The differing verbs (search/get/synthesize/generate) accurately reflect distinct actions rather than introducing inconsistency.
Four tools is on the lean side but each earns its place in the create-a-test-hire workflow. It fits the narrow scope well, though one or two more (e.g. cleanup) could round it out.
The search-to-hire path is fully covered end to end. The only notable gap is teardown/cleanup of a hired test worker or updating it afterward, which agents may need for repeated test runs.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Hosted MCP endpoint with realistic fake data for prototyping agents. 12 tools, no setup.
isolved and ApplicantPro jobs, tenant discovery, and change detection as an MCP server.
AI-native mock API server with MCP. Create REST/SOAP mocks from Claude, Cursor, or Windsurf.
Build, validate, and manage API simulations in WireMock Cloud from MCP-compatible AI agents.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables local prototyping of Cubi integrations with a mock HTTP server, MCP tools for lifecycle management, and a browser UI for workflow testing without real sandbox credentials.1-
- FlicenseNot gradedqualityCmaintenanceProvides deterministic mock customer health, product usage, and recommended playbook data via three MCP tools for a Customer Success Orchestrator demo.-
- FlicenseNot gradedqualityCmaintenanceProvides FHIR resource validation, synthetic test fixture generation, and HIPAA-safe logging review as MCP tools for AI agents.-
- FlicenseNot gradedqualityBmaintenanceMCP server that provides mock APIs and deterministic seed data for ERP/OMS, WMS, and CRM systems, enabling supply chain data exploration and integration testing.-