281 lines
5.8 KiB
Markdown
281 lines
5.8 KiB
Markdown
Got it — this time I’ll do exactly what you asked for, **no abstraction, no governance talk, no “what MCP is”**.
|
||
|
||
You already restructured the **Workday MCP guide** well. What’s missing (same as with the Identity guide earlier) is **hands‑on, “do this → then this” build steps** for the MCP server itself.
|
||
|
||
Below I’ll:
|
||
|
||
1. **Confirm whether you’re misunderstanding MCP (short answer: no)**
|
||
2. **Show the concrete steps to build the Workday MCP server**
|
||
3. **Map those steps directly into your existing guide**
|
||
4. **Call out where to stop adding steps (on purpose)**
|
||
|
||
***
|
||
|
||
## 1. First: are you misunderstanding how MCP works?
|
||
|
||
**You’re not misunderstanding — you were just one layer too high.**
|
||
|
||
Your guides correctly describe:
|
||
|
||
* governance
|
||
* scope
|
||
* phases
|
||
* guardrails
|
||
|
||
What they *don’t yet show* is this missing sentence:
|
||
|
||
> “An MCP server is just a small program you write that wraps your existing Workday API calls and exposes them as tools.”
|
||
|
||
There is **no magic Workday ↔ MCP connector**.
|
||
You **build** it, the same way you’d build:
|
||
|
||
* a small API service
|
||
* a script wrapper
|
||
* a microservice
|
||
|
||
MCP just standardizes:
|
||
|
||
* how tools are declared
|
||
* how clients discover them
|
||
* how results are returned
|
||
|
||
Once that clicks, everything makes sense.
|
||
|
||
***
|
||
|
||
## 2. The actual steps to create a Workday MCP server (READ‑ONLY)
|
||
|
||
I’ll show this in **Python**, because it’s the fastest path and matches MCP’s reference docs.
|
||
|
||
### ✅ Step 1 — Create a project
|
||
|
||
```bash
|
||
mkdir workday-mcp
|
||
cd workday-mcp
|
||
uv init
|
||
uv venv
|
||
uv add "mcp[cli]" httpx
|
||
```
|
||
|
||
What this does:
|
||
|
||
* sets up Python
|
||
* installs the official MCP SDK
|
||
* installs `httpx` for REST calls to Workday
|
||
|
||
✅ This is your MCP “runtime”.
|
||
|
||
***
|
||
|
||
### ✅ Step 2 — Create the MCP server file
|
||
|
||
Create `server.py`:
|
||
|
||
```python
|
||
from mcp.server.fastmcp import FastMCP
|
||
|
||
mcp = FastMCP("workday-mcp")
|
||
|
||
if __name__ == "__main__":
|
||
mcp.run(transport="stdio")
|
||
```
|
||
|
||
Run it:
|
||
|
||
```bash
|
||
uv run python server.py
|
||
```
|
||
|
||
You now have:
|
||
|
||
* a real MCP server
|
||
* speaking MCP over stdio
|
||
* with **zero tools yet**
|
||
|
||
This is the MCP equivalent of “hello world”.
|
||
|
||
***
|
||
|
||
### ✅ Step 3 — Add a real Workday READ tool
|
||
|
||
This is the **missing piece you were expecting**.
|
||
|
||
You now write **normal Python code** that:
|
||
|
||
1. calls Workday REST
|
||
2. returns structured data
|
||
|
||
Example: `workday.getWorkerStatus`
|
||
|
||
```python
|
||
import httpx
|
||
from mcp.server.fastmcp import FastMCP
|
||
|
||
mcp = FastMCP("workday-mcp")
|
||
|
||
WORKDAY_BASE = "https://wdX-impl-services1.workday.com/ccx/api/v1/YOUR_TENANT"
|
||
TOKEN = "READ_ONLY_TOKEN"
|
||
|
||
@mcp.tool()
|
||
async def workday_get_worker_status(worker_id: str) -> dict:
|
||
"""
|
||
Return employment status for a worker.
|
||
"""
|
||
headers = {"Authorization": f"Bearer {TOKEN}"}
|
||
async with httpx.AsyncClient() as client:
|
||
r = await client.get(
|
||
f"{WORKDAY_BASE}/workers/{worker_id}",
|
||
headers=headers,
|
||
)
|
||
r.raise_for_status()
|
||
data = r.json()
|
||
|
||
return {
|
||
"worker_id": worker_id,
|
||
"status": data.get("employmentStatus"),
|
||
"effective_date": data.get("effectiveDate"),
|
||
}
|
||
|
||
if __name__ == "__main__":
|
||
mcp.run(transport="stdio")
|
||
```
|
||
|
||
That’s it.
|
||
|
||
✅ You just built a **real Workday MCP server**
|
||
✅ It’s **read‑only**
|
||
✅ It exposes a **tool**
|
||
✅ The AI can now call it
|
||
|
||
***
|
||
|
||
### ✅ Step 4 — Add more tools (your Phase 2)
|
||
|
||
Each tool is just another function:
|
||
|
||
```python
|
||
@mcp.tool()
|
||
async def workday_get_manager(worker_id: str) -> dict:
|
||
"""Return manager info."""
|
||
```
|
||
|
||
```python
|
||
@mcp.tool()
|
||
async def workday_get_org_attributes(worker_id: str) -> dict:
|
||
"""Return department, cost center, location."""
|
||
```
|
||
|
||
This maps **1:1** with your guide’s approved tool list.
|
||
|
||
***
|
||
|
||
### ✅ Step 5 — Test with an MCP client
|
||
|
||
Use:
|
||
|
||
* MCP Inspector
|
||
* Claude Desktop
|
||
* any MCP-compatible client
|
||
|
||
The client will:
|
||
|
||
1. discover your tools
|
||
2. show their schemas
|
||
3. call them with arguments
|
||
4. receive structured output
|
||
|
||
At this point, **the MCP part is done**.
|
||
|
||
Everything after this is:
|
||
|
||
* policy
|
||
* correlation
|
||
* workflow
|
||
* approvals
|
||
|
||
Which your guide already covers well.
|
||
|
||
***
|
||
|
||
## 3. How to flesh out your Workday guide (exact inserts)
|
||
|
||
Here’s **what to add**, and **where**, without rewriting your doc.
|
||
|
||
***
|
||
|
||
### 🔹 Add to **Phase 1: Integration foundation**
|
||
|
||
```md
|
||
#### Implementation steps
|
||
|
||
1. Create a new MCP project using the official MCP SDK.
|
||
2. Initialize the MCP server using the FastMCP class.
|
||
3. Configure the server to run over stdio transport.
|
||
4. Verify the server starts and responds to MCP handshake requests.
|
||
```
|
||
|
||
***
|
||
|
||
### 🔹 Add to **Phase 2: Tool surface definition**
|
||
|
||
```md
|
||
#### Tool implementation steps
|
||
|
||
1. For each approved tool:
|
||
- Implement a Python function that calls the Workday REST API.
|
||
- Restrict the API call to GET-only endpoints.
|
||
- Return a structured dictionary containing only approved fields.
|
||
|
||
2. Decorate each function with @mcp.tool().
|
||
3. Restart the MCP server and confirm tools are discoverable.
|
||
```
|
||
|
||
***
|
||
|
||
### 🔹 Add to **Phase 3: Read-only validation**
|
||
|
||
```md
|
||
#### Validation steps
|
||
|
||
1. Invoke each tool with known worker IDs.
|
||
2. Compare MCP output with direct Workday UI/API results.
|
||
3. Confirm no write operations occur.
|
||
4. Log all requests and responses for audit review.
|
||
```
|
||
|
||
***
|
||
|
||
## 4. Where to STOP adding step-by-steps (important)
|
||
|
||
Do **not** add step-by-steps for:
|
||
|
||
* OAuth setup details
|
||
* Token storage
|
||
* API error handling
|
||
* Retry logic
|
||
* Hosting strategy
|
||
|
||
Those belong in:
|
||
|
||
* a **developer runbook**
|
||
* or **code comments**
|
||
|
||
Your guide should stay:
|
||
✅ implementation‑guided
|
||
❌ not a code tutorial
|
||
|
||
***
|
||
|
||
## 5. The mental model that makes this click
|
||
|
||
> **MCP = plugin system for AI**
|
||
|
||
* You write the plugin (MCP server)
|
||
* MCP defines the interface
|
||
* AI calls your functions
|
||
* You control everything else
|
||
|
||
Once you build **one real tool**, the rest becomes obvious.
|
||
|
||
***
|