POD Governance — MCP Setup & Configuration

v2026-06

MCP Setup & Configuration

Connect Claude Desktop, Claude Code CLI, or the AiDE VS Code plugin to the POD Governance MCP server. Choose Remote Servers UI for instant zero-setup access, or stdio / .mcp.json for a full local development workflow.

Prerequisites

  1. Build the MCP server (only needed for stdio / local mode — skip if using Remote Servers UI):
    cd src/mcp
    npm install
    npm run build
    # Output: src/mcp/dist/index.js
  2. Generate an MCP Access Token (PAT) — see the section below. This replaces the old raw-JWT approach; PATs are long-lived and individually revocable.

Generating an Access Token

MCP clients authenticate with a Personal Access Token (PAT) — a long-lived, individually revocable credential that acts on behalf of the user who created it (inheriting their role and project access).

Option A — Self-service (recommended for individuals)

The token always acts as you. You can revoke any of your own tokens from the same screen at any time.

Option B — Admin-issued (service accounts & oversight)

Use this when issuing tokens for service accounts (shared/non-human identities for team automation or CI/CD pipelines), or when an admin needs to view or revoke any user's token across the entire organisation. Requires the Admin role.

Security note Tokens are stored as a SHA-256 hash with only a short display prefix kept in the clear. Revoke a token at any time — it stops working on the next request. Every call is recorded in the MCP Interaction Log (identity, tool, endpoint, status, duration). Admins can also revoke individual users' self-service tokens from the same screen.

Comparison: Option A vs Option B

Option A — Self-serviceOption B — Admin-issued
Who can createAny signed-in userAdmin role only
Acts asThe creator (always)Any chosen Owner identity
Best forIndividual developer / analystService accounts, CI/CD, shared team tools
Where to createProfile page (avatar → Profile)Admin Portal → AI Integration → MCP Access Tokens
Visible to adminYes — admin can revokeYes — admin created it
Token formatpgmcp_… — same format, same auth path

Environment Variables

VariableRequiredDescriptionExample
MCP_API_BASE_URL Yes Base URL of the POD Governance REST API http://localhost:3001/api/v1
MCP_API_TOKEN Yes MCP Access Token (PAT) generated in the portal — pgmcp_… pgmcp_3f9a…
MCP_CLIENT No Client label recorded in the interaction log (default claude-desktop) aide-vscode
MCP_PORT No If set, run as an HTTP (Streamable HTTP) server on this port instead of stdio 3100

Transports: stdio (default) vs HTTP

The server picks its transport from the environment:

# Run the server in HTTP mode locally
cd src/mcp
MCP_PORT=3100 MCP_API_BASE_URL=http://localhost:3001/api/v1 MCP_API_TOKEN=pgmcp_… node dist/index.js
# → POST/GET/DELETE http://localhost:3100/mcp  (GET /health for a liveness check)

The HTTP endpoint runs the MCP Streamable HTTP transport in stateless mode: every POST /mcp is self-contained — the server spins up a fresh instance, handles the one JSON-RPC message, and returns plain JSON. No Mcp-Session-Id is issued or required, so clients never have to track a session. GET /mcp and DELETE /mcp return 405 Method Not Allowed (there is no server→client SSE stream and no session to terminate).

Why stateless? The earlier stateful design kept sessions in an in-memory map keyed by Mcp-Session-Id. Behind iisnode (multiple worker processes + app-pool recycles) the worker that handled initialize often wasn't the one that received the follow-up tools/call, so the session wasn't found and the server returned 400 Bad Request: no valid session ID. Stateless mode removes that failure mode entirely.

Hosted on Dev / Staging

The CI/CD pipeline deploys the HTTP transport to the Azure VM as an iisnode IIS sub-app:

Dev
http://vishnuvm.centralindia.cloudapp.azure.com/PODGovernance_Dev/mcp
Staging
http://vishnuvm.centralindia.cloudapp.azure.com/PODGovernance_Staging/mcp
iisnode & streaming Because the transport is stateless and every tool result is plain JSON over POST, the hosted iisnode endpoint works without any session affinity or SSE streaming. The trade-off is that server-initiated progress notifications (which need a server→client stream) aren't delivered over HTTP — tool calls still return their full result normally. If you need live progress, run dist/index.js standalone with MCP_PORT, or use the stdio transport.

Per-user auth over HTTP

An HTTP client may authenticate as itself by sending its own PAT on each request:

Authorization: Bearer pgmcp_…

The server forwards that token per-request to the REST API, so the call runs as that user — inheriting their role/project access and attributing correctly in the MCP Interaction Log. If no Authorization header is present the server falls back to the shared MCP_API_TOKEN from its environment.


Claude Desktop

Add a pod-governance entry to the mcpServers block in your Claude Desktop config file.

File location:

{
  "mcpServers": {
    "pod-governance": {
      "command": "node",
      "args": ["C:/Projects/ValueLabs/PODGovernance/src/mcp/dist/index.js"],
      "env": {
        "MCP_API_BASE_URL": "http://localhost:3001/api/v1",
        "MCP_API_TOKEN": "pgmcp_YOUR_TOKEN_HERE",
        "MCP_CLIENT": "claude-desktop"
      }
    }
  }
}

Restart Claude Desktop after saving the file.

Claude Code CLI

claude mcp add pod-governance \
  --env MCP_API_BASE_URL=http://localhost:3001/api/v1 \
  --env MCP_API_TOKEN=pgmcp_YOUR_TOKEN_HERE \
  --env MCP_CLIENT=claude-code \
  -- node /path/to/PODGovernance/src/mcp/dist/index.js

Or add directly to your project's .mcp.json:

{
  "mcpServers": {
    "pod-governance": {
      "command": "node",
      "args": ["./src/mcp/dist/index.js"],
      "env": {
        "MCP_API_BASE_URL": "http://localhost:3001/api/v1",
        "MCP_API_TOKEN": "pgmcp_YOUR_TOKEN_HERE",
        "MCP_CLIENT": "claude-code"
      }
    }
  }
}

AiDE Plugin — stdio (.vscode/mcp.json)

AiDE reads MCP server configuration from a .vscode/mcp.json file in the workspace root — separate from claude_desktop_config.json — so the server is automatically available to every developer who opens the workspace.

Pointing to Dev/Staging instead of local

"MCP_API_BASE_URL": "http://vishnuvm.centralindia.cloudapp.azure.com/PODGovernance_Dev/api/v1"

Verifying the connection

After saving .vscode/mcp.json, AiDE will surface the pod-governance server in its tool palette. Ask AiDE:

"List all active cycles for my projects"
"What's this week's Priorities & Achievements summary?"
"Show me the review status for project proj-123"

If the server fails to connect, check the AiDE output panel for the stderr line: POD Governance MCP server running on stdio. If you see a 401 Authentication failed, generate a new token from your Profile page and update MCP_API_TOKEN in .vscode/mcp.json.


AiDE Plugin — Remote Servers UI Recommended — no build needed

The AiDE plugin's Remote Servers settings panel connects directly to the hosted MCP HTTP endpoint — no local node process, no build step, no .vscode/mcp.json file required.

When to use which approach

.vscode/mcp.json stdio

  • MCP process runs locally via node
  • Requires npm run build first
  • Auth via MCP_API_TOKEN env var
  • ✅ Full stdio streaming — all progress events
  • Best for: full local development workflow
All 33 POST-based tool calls work normally over the hosted endpoint. Only server-initiated SSE progress notifications are degraded due to iisnode response buffering.

Steps

Per-environment Server URLs

Dev
http://vishnuvm.centralindia.cloudapp.azure.com/PODGovernance_Dev/mcp
Staging
http://vishnuvm.centralindia.cloudapp.azure.com/PODGovernance_Staging/mcp
Local (HTTP mode)
http://localhost:3100/mcp (requires MCP_PORT=3100)

Troubleshooting

SymptomFix
401 Authentication failed Token revoked, expired, or mistyped — generate a new PAT from your Profile page
403 Token is read-only on forward/return/submit Generate a write-scope token
Server listed but no tools appear Check the AiDE output panel; verify the health endpoint: GET …/PODGovernance_Dev/mcp/health

Available Tools (34)

Cycle Workflow

list_cycles
List cycles for a project, filtered by status
get_cycle
Get full cycle details (ups, downs, audit log)
get_review_chain
Get the 6-level approval chain for a cycle
forward_cycle
Forward a cycle to the next reviewer
return_cycle
Return a cycle for revision (comment required)

Ups & Downs Items CRUD

list_cycle_items
List a cycle's items, grouped into ups & downs
add_cycle_item
Add an Up or Down item to a cycle
update_cycle_item
Edit the text of an existing item
delete_cycle_item
Soft-delete an item (keeps audit trail)

Priorities & Achievements

get_current_week
Get the current Priorities & Achievements week ID
get_pa_items
Get Priorities & Achievements items for a week, optionally by PL
submit_pa
Submit your Priorities & Achievements for bilateral review
bilateral_approve
Approve a PL's Priorities & Achievements submission
bilateral_return
Return a Priorities & Achievements submission for revision
submit_pl_items
Create Priorities & Achievements items in bulk (priorities + achievements, incl. AiDE flag)
update_pa_item
Edit the text of an existing Priorities & Achievements item
delete_pa_item
Delete a Priorities & Achievements item (AiDE priority is protected)

Reports & Admin

get_reports
Retrieve governance reports by type
get_audit_log
Get audit log for a specific cycle
list_projects
List all accessible projects

Admin Portal — Projects / PODs / Users admin token

These run under /admin/* and only succeed with an admin or PMO token — any other token gets a 403. Delete is guarded: a project with active cycles, or a POD with projects, returns a 409 (deactivate via the matching update tool instead).

admin_list_projects
All projects with assignments, members & stats
admin_get_project
One project with full member detail
admin_create_project
Create a project (name, POD, sales SPOC, …)
admin_update_project
Edit fields / reassign roles / replace members
admin_delete_project
Delete a project (blocked if active cycles)
admin_list_pods
PODs with owner, cluster head & project counts
admin_create_pod
Create a POD (name, owner, cluster head)
admin_update_pod
Edit a POD / deactivate it
admin_delete_pod
Delete a POD (blocked if it has projects)
admin_list_users
All users with roles & status (filterable)
admin_update_user
Change a user's roles and/or account status
admin_set_user_projects
Replace a user's project memberships
admin_invite_user
Invite a new user by email (create-user path)

Available Resources (3)

URIDescription
pods://projectsAll projects accessible to the authenticated user
pods://cycles/{projectId}/activeActive cycle for a project
pods://cycles/{id}Full detail for a specific cycle

Pre-built Prompts (3)

PromptArgsDescription
my_pending_cyclesprojectId?List cycles where you are the current reviewer
week_pa_summaryweekId?Summarise all Priorities & Achievements submissions for a week
cycle_review_statusprojectIdOne-paragraph status brief for the active cycle

Progress Notifications

The data-heavy read tools (list_cycles, get_cycle, get_reports, get_audit_log, get_pa_items) emit MCP notifications/progress updates while they work — a "started" message and a "completed" message with the record count. This is opt-in per the MCP spec: a client only receives them if it includes a progressToken in the request _meta. Clients that don't request progress are unaffected.

Usage Examples

"List all active cycles for project proj-123"
→ list_cycles(projectId: "proj-123", status: "pl_submitted")

"Forward cycle cycle-456 with comment 'Reviewed and approved'"
→ forward_cycle(cycleId: "cycle-456", comment: "Reviewed and approved")

"What are this week's Priorities & Achievements submissions?"
→ get_current_week() → get_pa_items(weekId: )

"Show me the cycle review status for project proj-123"
→ prompt: cycle_review_status(projectId: "proj-123")

Prompt Library — by task

Everything the assistant can do, phrased the way you'd actually ask. Each example shows a natural-language prompt and the tool call (or chain of calls) it resolves to. The assistant acts as you — it can only do what your role and token scope allow, and every call is recorded in the MCP Interaction Log. Write-tools (add_*, update_*, delete_*, forward_*, return_*, submit_*, bilateral_*) require a write-scope token.

1. Discover what needs your attention

"Which cycles am I the current reviewer for?"
→ prompt: my_pending_cycles()

"List the projects I have access to"
→ list_projects()

"Show all returned cycles for project proj-123 that need rework"
→ list_cycles(projectId: "proj-123", status: "returned")

"What's the latest cycle for the Acme POD and who has it now?"
→ list_projects() → list_cycles(projectId: , limit: 1) → get_review_chain(cycleId: )

2. Read a cycle in detail

"Open cycle cycle-456 and summarise the ups and downs"
→ get_cycle(cycleId: "cycle-456")

"Just list the items on cycle-456, separated into ups and downs"
→ list_cycle_items(cycleId: "cycle-456")

"Show the full approval chain for cycle-456 with names and timestamps"
→ get_review_chain(cycleId: "cycle-456")

"Who changed what on cycle-456?"
→ get_audit_log(cycleId: "cycle-456")

"Include deleted items too when you list cycle-456"
→ list_cycle_items(cycleId: "cycle-456", includeDeleted: true)

3. Edit Ups & Downs items create / update / delete

"Add an Up to cycle-456: 'Closed the migration two days early'"
→ add_cycle_item(cycleId: "cycle-456", type: "up", text: "Closed the migration two days early")

"Add a Down: 'Staging environment was unstable all week'"
→ add_cycle_item(cycleId: "cycle-456", type: "down", text: "Staging environment was unstable all week")

"Reword item item-9 to 'Onboarded two new engineers'"
→ update_cycle_item(cycleId: "cycle-456", itemId: "item-9", text: "Onboarded two new engineers")

"Remove item item-12 from the cycle"
→ delete_cycle_item(cycleId: "cycle-456", itemId: "item-12")

"Draft my weekly ups and downs for cycle-456 from these notes: …"
→ (assistant proposes items, then) add_cycle_item(…) × N  — review before sending

4. Move a cycle through the approval chain

"Forward cycle-456 to the next reviewer"
→ forward_cycle(cycleId: "cycle-456")

"Approve cycle-456 — note 'Numbers look solid, good quarter'"
→ forward_cycle(cycleId: "cycle-456", comment: "Numbers look solid, good quarter")

"Send cycle-456 back to the PM — the client risk needs more detail"
→ return_cycle(cycleId: "cycle-456", comment: "Please expand on the client risk before resubmitting")

"Give me a one-paragraph brief on the active cycle for proj-123 before I decide"
→ prompt: cycle_review_status(projectId: "proj-123")

5. Draft & submit your Priorities & Achievements

"What Priorities & Achievements week are we in?"
→ get_current_week()

"Add my 3 priorities and 3 achievements for this week" (one must be the AiDE priority)
→ get_current_week() → submit_pl_items(weekId: , items: [
    { type: "priority",    text: "Ship the billing revamp",    category: "delivery" },
    { type: "priority",    text: "Adopt AiDE across the POD",   category: "ai", isAide: true },
    { type: "priority",    text: "Hire one senior engineer",    category: "hiring" },
    { type: "achievement", text: "Cut build time by 40%" },
    { type: "achievement", text: "Closed 3 client escalations" },
    { type: "achievement", text: "Mentored 2 juniors to merge" }
  ])

"Fix a typo in priority item pi-7"
→ update_pa_item(weekId: , itemId: "pi-7", text: "Adopt AiDE across the whole POD")

"Delete achievement item pi-11"
→ delete_pa_item(weekId: , itemId: "pi-11")
  (note: the mandatory AiDE priority can be edited but not deleted)

"Submit my Priorities & Achievements for bilateral review"
→ get_current_week() → submit_pa(weekId: )

6. Review your team's Priorities & Achievements (PM / SPOC / POD Owner)

"Summarise every Priorities & Achievements submission for this week"
→ prompt: week_pa_summary()

"Show me just Priya's priorities for this week"
→ get_current_week() → get_pa_items(weekId: , plId: )

"Approve Priya's Priorities & Achievements — 'Strong, AiDE goal is concrete'"
→ bilateral_approve(weekId: , plId: , comment: "Strong, AiDE goal is concrete")

"Return Arun's Priorities & Achievements — achievements need metrics"
→ bilateral_return(weekId: , plId: , comment: "Please quantify the achievements")

7. Reports & audit

"Give me the governance summary report"
→ get_reports(type: "summary")

"Cycle throughput for project proj-123 between Jan and Mar"
→ get_reports(type: "cycles", projectId: "proj-123", from: "2026-01-01", to: "2026-03-31")

"What's our return rate this quarter?"
→ get_reports(type: "return-rate", from: "2026-04-01", to: "2026-06-30")

"Show the weekly Priorities & Achievements category breakdown"
→ get_reports(type: "pa-categories")

"Pull the audit log for cycle-456"
→ get_audit_log(cycleId: "cycle-456")

get_reports types: summary, cycles, trend, return-rate, pa-weekly, pa-categories, pa-summary.

8. Administer projects, PODs & users admin token

"List every active project in the Core POD"
→ admin_list_projects(podId: , status: "active")

"Create a project 'Acme Migration' in the Core POD with Maya as sales SPOC"
→ admin_list_pods() → admin_list_users(role: "sales_spoc")
  → admin_create_project(name: "Acme Migration", podId: , salesSpocId: )

"Make Raj the delivery SPOC on project proj-123"
→ admin_update_project(projectId: "proj-123", deliverySpocId: )

"Deactivate project proj-123" (safe alternative to delete)
→ admin_update_project(projectId: "proj-123", status: "inactive")

"Spin up a new POD 'Payments' owned by Dilip"
→ admin_create_pod(name: "Payments", podOwnerId: )

"Promote user u-42 to PM and POD owner"
→ admin_update_user(userId: "u-42", roles: ["pm", "pod_owner"])

"Add user u-42 to proj-123 as a PL"
→ admin_set_user_projects(userId: "u-42", memberships: [{ projectId: "proj-123", memberType: "pl" }])

"Invite priya@acme.com as a Project Lead on proj-123"
→ admin_invite_user(email: "priya@acme.com", role: "pl", projectIds: ["proj-123"])

9. End-to-end conversational flows

"Walk my cycle from draft to submitted: add these 3 ups and 2 downs, then forward it"
→ add_cycle_item(…) × 5 → forward_cycle(cycleId: , comment: "Ready for PM review")

"Check if anything's waiting on me, open the first one, and brief me"
→ my_pending_cycles() → get_cycle(cycleId: ) → get_review_chain(cycleId: )

"Build my Priorities & Achievements for the week from last week's plus these changes, then submit"
→ get_current_week() → get_pa_items(weekId: ) → submit_pl_items(…) → submit_pa(weekId: )

"Onboard a new POD: create it, add a project under it, and invite its lead"
→ admin_create_pod(…) → admin_create_project(…) → admin_invite_user(…)

Managing Tokens & Reviewing Activity

TaskWhere
Generate / list / revoke your own tokensProfile page — click your avatar in the top nav (/profile)
Issue service-account tokens / manage any user's tokenAdmin Portal → AI Integration → MCP Access Tokens
See what an assistant actually didAdmin Portal → AI Integration → MCP Interaction Log
Rotate a tokenGenerate a new one, update your config, then revoke the old one
A leaked tokenRevoke immediately — it stops working on the next request

The interaction log records every token-authenticated call — including reads, writes, reports, and denied (403) calls — with the identity, tool name, endpoint, status, and duration. The MCP server sends an X-MCP-Tool header per call so the log shows the semantic tool name (e.g. forward_cycle) rather than just the HTTP path.

Troubleshooting

SymptomCauseFix
Authentication failed — check MCP_API_TOKEN (401) Token revoked, expired, or mistyped Generate a new token in the portal and update your config
Token is read-only (403) on a forward/return/submit Token has read scope Generate a write-scope token
Forbidden (403) on a specific cycle The owner identity isn't the current reviewer Use a token owned by the correct user/role
Server listed but no tools appear (Remote Servers UI) MCP server unreachable or iisnode down Check GET …/PODGovernance_Dev/mcp/health

Environment URLs

EnvironmentMCP EndpointAPI Base URL
Local dev http://localhost:3100/mcp http://localhost:3001/api/v1
Dev (Azure VM) …/PODGovernance_Dev/mcp …/PODGovernance_Dev/api/v1
Staging (Azure VM) …/PODGovernance_Staging/mcp …/PODGovernance_Staging/api/v1
Production https://.azurewebsites.net/mcp https://.azurewebsites.net/api/v1

Full VM hostname: vishnuvm.centralindia.cloudapp.azure.com