approval-mcpapp
by groveale
README.md
# Access Request & Approval Workflow — MCP App
An MCP (Model Context Protocol) server that implements a multi-stage employee access request and approval workflow. Employees request system access, and managers and IT admins review and approve or reject requests — all from within an MCP-compatible host like VS Code Copilot Chat.
  
---
## Features
- **Multi-stage approval pipeline** — Requested → Manager Review → IT Review → Granted/Rejected
- **Interactive UI panels** — Rich React-based forms and dashboards served as MCP app resources
- **6 supported systems** — GitHub, SAP, Production Database, Azure DevOps, Salesforce, Jira
- **Persistent storage** — Azure Table Storage (Azurite emulator for local dev)
---
## Architecture
```
┌──────────────────────────────────────────────────┐
│ MCP Host (e.g. VS Code Copilot Chat) │
│ │
│ ┌─────────────┐ ┌──────────────┐ │
│ │ Request Form │ │ Approval │ │
│ │ (React) │ │ Panel (React)│ │
│ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │
│ └────────┬───────┘ │
│ │ callServerTool │
└──────────────────┼────────────────────────────────┘
▼
┌─────────────────────────────────┐
│ MCP Server (Express) │
│ POST /mcp │
│ │
│ Tools: submit-request │
│ submit-decision │
│ get-request │
└──────────────┬──────────────────┘
│
▼
┌───────────────────┐
│ Azure Table │
│ Storage │
│ (Azurite local) │
└───────────────────┘
```
---
## Prerequisites
- **Node.js** 22 or later
- **npm** 10 or later
---
## Getting Started
### 1. Install dependencies
```bash
npm install
```
### 2. Start the Azurite storage emulator
In a separate terminal:
```bash
npm run start:azurite
```
This starts the Azure Table Storage emulator on `http://127.0.0.1:10002`. Data is stored in the `.azurite/` directory.
### 3. Seed sample data (optional)
```bash
npm run seed
```
Loads three sample requests (REQ-001 through REQ-003) from `fixtures/` so you can explore the app immediately.
### 4. Build and run
```bash
npm start
```
The MCP server starts at **`http://localhost:3001/mcp`**.
---
## Development
Start the dev server with hot reload for both UI and backend:
```bash
npm run dev
```
This runs concurrently:
- **UI watcher** — Rebuilds HTML bundles on file changes in `ui/` and `src/`
- **Server watcher** — Restarts the MCP server on backend file changes
---
## Available Scripts
| Command | Description |
|---|---|
| `npm start` | Full build + start the server |
| `npm run build` | Type-check, build UI bundles, compile server TypeScript |
| `npm run serve` | Run the already-built server |
| `npm run dev` | Watch mode with hot reload |
| `npm run start:azurite` | Start Azurite Table Storage emulator |
| `npm run seed` | Seed sample data into Azurite |
---
## MCP Tools
### Frontend Tools (return interactive UI)
#### `request-access`
Opens the access request form for employees.
| Parameter | Type | Required | Description |
|---|---|---|---|
| `employeeName` | string | No | Pre-fill the employee name |
| `employeeEmail` | string | No | Pre-fill the employee email |
**Example prompt:** _"I need to request access to GitHub"_
#### `approve-access`
Opens the approval panel for managers and IT admins to review pending requests.
| Parameter | Type | Required | Description |
|---|---|---|---|
| `requestId` | string | No | View a specific request, or leave blank to see all pending |
**Example prompt:** _"Show me pending access requests to approve"_
### Backend Tools (called by UI widgets)
| Tool | Parameters | Description |
|---|---|---|
| `submit-request` | `employeeName`, `employeeEmail`, `system`, `role`, `justification` | Creates a new access request |
| `submit-decision` | `requestId`, `decision` (approve/reject), `reviewer`, `comment` | Records an approval or rejection |
| `get-request` | `requestId` | Fetches a single request by ID |
---
## Workflow Stages
Each access request progresses through these stages:
```
┌───────────┐ ┌────────────────┐ ┌────────────┐ ┌─────────┐
│ Requested │───▶│ Manager Review │───▶│ IT Review │───▶│ Granted │
└───────────┘ └───────┬────────┘ └─────┬──────┘ └─────────┘
│ │
▼ ▼
┌──────────┐ ┌──────────┐
│ Rejected │ │ Rejected │
└──────────┘ └──────────┘
```
1. **Requested** — Employee submits the form
2. **Manager Review** — Direct manager approves or rejects
3. **IT Review** — IT admin performs final review
4. **Granted** — Access is provisioned
5. **Rejected** — Request denied (can happen at either review stage)
---
## Supported Systems and Roles
| System | Available Roles |
|---|---|
| GitHub | Read, Write, Admin |
| SAP | Finance Viewer, Finance Editor, Admin |
| Production Database | Read-Only, Read-Write, DBA |
| Azure DevOps | Reader, Contributor, Project Admin |
| Salesforce | Viewer, Editor, Admin |
| Jira | Viewer, Developer, Project Lead |
---
## Data Model
### Access Request
```json
{
"id": "REQ-001",
"employeeName": "Alice Johnson",
"employeeEmail": "alice@contoso.com",
"system": "GitHub",
"role": "Write",
"justification": "Need write access for the frontend repo",
"status": "Manager Review",
"createdAt": "2026-03-31T10:00:00.000Z",
"updatedAt": "2026-03-31T10:00:00.000Z",
"timeline": [
{
"stage": "Requested",
"status": "completed",
"actor": "Alice Johnson",
"timestamp": "2026-03-31T10:00:00.000Z"
},
{
"stage": "Manager Review",
"status": "current",
"timestamp": "2026-03-31T10:00:00.000Z"
}
]
}
```
---
## Environment Variables
| Variable | Description | Default |
|---|---|---|
| `PORT` | HTTP server port | `3001` |
| `AZURE_STORAGE_CONNECTION_STRING` | Azure Table Storage connection string | Azurite local default |
| `NODE_ENV` | Set to `development` for watch mode | — |
---
## Project Structure
```
├── main.ts # Express app entry point, /mcp endpoint
├── server.ts # MCP server definition, tool/resource registration
├── mock-data/
│ └── requests.ts # Data access layer (Azure Table Storage)
├── src/
│ ├── global.css # Shared styles
│ ├── request-form/
│ │ └── App.tsx # Employee request form UI
│ └── approval-panel/
│ └── App.tsx # Manager/admin approval panel UI
├── ui/
│ ├── request-form.html # Entry HTML for request form
│ └── approval-panel.html # Entry HTML for approval panel
├── fixtures/
│ ├── access-requests.json # Sample request data for seeding
│ └── counters.json # Counter seed data
├── scripts/
│ └── seed-data.ts # Seed script for loading fixtures
├── vite.config.ts # Vite configuration
├── tsconfig.json # TypeScript config (type-checking)
├── tsconfig.server.json # TypeScript config (server compilation)
└── package.json
```
---
## Tech Stack
| Layer | Technology |
|---|---|
| MCP Framework | `@modelcontextprotocol/sdk`, `@modelcontextprotocol/ext-apps` |
| Server | Express 5, TypeScript |
| UI | React 19, Fluent UI React v9 |
| Storage | Azure Table Storage (`@azure/data-tables`) |
| Local Emulator | Azurite |
| Build | Vite, `vite-plugin-singlefile` |
| Validation | Zod |
This server cannot be deployed
Maintenance
ActivityStale
ResponsivenessNo issues