Synthire
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., "@Synthire Hire 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.
Inputs: country (required).
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.
Inputs: employee_id (required).
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.
Inputs: name (required). Returns: result
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.
Inputs: email (required), country (required), last_name (required), first_name (required), +5 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
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
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.
Sandbox workspace tools: search, file read, DB queries, integrations. Returns synthetic data.
AI-native mock API server with MCP. Create REST/SOAP mocks from Claude, Cursor, or Windsurf.
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 gradedqualityDmaintenanceProvides deterministic mock customer health, product usage, and recommended playbook data via three MCP tools for a Customer Success Orchestrator demo.-
- FlicenseNot gradedqualityCmaintenanceEnables read-only access to Workday HCM data such as workers, organizations, locations, job profiles, and cost centers through MCP tools an LLM can call.-
- FlicenseNot gradedqualityCmaintenanceEnables answering authorized HR questions by exposing a set of read-only MCP tools over synthetic SuccessFactors-style data, with optional AI agent orchestration and configurable modes for mock, demo, or real test tenant usage.-