npm package: @nestpilot/mcp-app
Description: NestPilot MCP App — Retirement planning tools and interactive views
Latest version: 1.0.2

# NestPilot MCP App

NestPilot retirement planning tools and interactive apps, distributed as an MCP server via the `@modelcontextprotocol/ext-apps` SDK. Runs in any MCP-compatible host (Claude Desktop, ChatGPT, GitHub Copilot, VS Code, MCPJam, basic-host).

Migrated from `apps/chatgpt-app/` (Python FastApps / OpenAI Apps SDK).

**Features**: FEAT-0052 (Medicare Guardian), FEAT-0001 (Plan Creation), FEAT-0002 (Forecast), FEAT-0003 (Scenarios), FEAT-0066 (Roth Conversion)

## Tools

### Planning Tools

| Tool | Visibility | Backend Endpoint | Purpose |
|------|-----------|------------------|---------|
| `create_plan` | model | `POST /api/plan/calc` | Quick retirement projection (balance, withdrawal, readiness score) |
| `run_forecast` | model | `POST /api/plan/forecast` | Comprehensive multi-account, multi-income forecast with yearly projections |
| `run_scenario` | model | `POST /api/plan/scenario/run` | What-if scenario analysis with plan deltas, component overrides, stress tests |
| `verify_forecast` | model | `POST /api/plan/forecast/verify` | Forecast verification with auditable calculation trace |
| `coach` | model | `POST /api/spring_ai/coach` | AI-powered retirement coaching and concept explanations |

### Roth Conversion Tools

| Tool | Visibility | Backend Endpoint | Purpose |
|------|-----------|------------------|---------|
| `optimize_roth_conversion` | model | `POST /api/tax/roth/max-conversion` | Multi-year Roth conversion strategy with tax analysis, IRMAA warnings, RMD impact |

**Note**: This tool is currently under development (FEAT-0066).

### Medicare Tools

| Tool | Visibility | Backend Endpoint | Purpose |
|------|-----------|------------------|---------|
| `medicare-guardian` | model + app | — (renders UI) | Launches the interactive Medicare Guardian UI |
| `medicare-analyze` | app (internal) | `POST /api/medicare/guardian/analyze` | Proxies analysis to NestPilot backend API |
| `email-subscribe` | app (internal) | `POST /api/medicare/subscribe` | Proxies email subscription to backend API |

### Agent Runtime Tools

| Tool | Visibility | Backend Endpoint | Purpose |
|------|-----------|------------------|---------|
| `nestpilot_list_skills` | model | `GET /skills` (agent-runtime) | Lists all available agent skills |
| `nestpilot_run_skill` | model | `POST /sessions/:id/messages` | Runs a specific agent skill within a session |
| `nestpilot_run_plan` | model | `POST /sessions/:id/messages` | Full retirement readiness assessment via retirement-readiness skill |

### Interactive Views

| View | Resource URI | Purpose |
|------|-------------|---------|
| `retirement-planner` | `ui://retirement-planner/planner-v2.html` | Interactive retirement planner with charts and scenario comparison |
| `verification-packet` | `ui://verification-packet/verification-packet.html` | Verification packet display for forecast audit trails |

## Quick Start

```bash
npm install
npm run build
cp .env.example .env
npm run serve:auth          # HTTP transport on port 3001 (auth enforced)
# or
npm run serve:auth:stdio    # stdio transport for Claude Desktop
```

## Testing the MCP Server

### 1. Test with Custom Script

```bash
# Build the MCP app first
npm run build

# Start the MCP server (HTTP transport with auth)
npm run serve:auth

# In another terminal, run the test script
node test-mcp-tools.mjs
```

The test script `test-mcp-tools.mjs` tests all major tools:
- `optimize_roth_conversion` (Roth optimization)
- `create_plan` (Quick projection)
- `run_forecast` (Multi-account forecast)
- `coach` (AI coaching)
- `nestpilot_list_skills` (Agent skills)
- `verify_forecast` (Verification)

### 2.Test with GitHub Copilot (VS Code)

Add to `.github/claude_desktop_config.json` or VS Code's MCP settings:

```json
{
  "mcpServers": {
    "nestpilot": {
      "command": "npx",
      "args": ["tsx", "C:\\git\\javapan\\nestpilot\\apps\\mcp-app\\main.ts", "--stdio"]
    }
  }
}
```

Then in GitHub Copilot Chat:
- "List available NestPilot tools"
- "Create a retirement plan for someone who is 45, wants to retire at 65, has $300k saved"
- "What's the 4% rule?" (tests coach tool)

### 3. Test with basic-host

```bash
# Terminal 1: Run this server
npm start

# Terminal 2: Run basic-host from the ext-apps repo
cd c:\git\ref\ext-apps\examples\basic-host
npm install
SERVERS='["http://localhost:3001/mcp"]' npm run start
# Open http://localhost:8080
```

### 4. Test with Claude Desktop

Add to `%APPDATA%\Claude\claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "nestpilot": {
      "command": "npx",
      "args": ["tsx", "C:\\git\\javapan\\nestpilot\\apps\\mcp-app\\main.ts", "--stdio"]
    }
  }
}
```

Restart Claude Desktop, then test:
- "What tools do you have from NestPilot?"
- "Help me plan my retirement. I'm 40, have $250k saved, contributing $2k/month"

### 5. Manual Testing with curl/PowerShell

```powershell
# List all tools
$payload = @{
    jsonrpc = "2.0"
    id = "test1"
    method = "tools/list"
    params = @{}
} | ConvertTo-Json

Invoke-RestMethod -Uri "http://localhost:3001/mcp" `
  -Method POST `
  -ContentType "application/json" `
  -Headers @{ Accept = "application/json, text/event-stream" } `
  -Body $payload

# Call create_plan tool
$payload = @{
    jsonrpc = "2.0"
    id = "test2"
    method = "tools/call"
    params = @{
        name = "create_plan"
        arguments = @{
            currentAge = 40
            retireAge = 65
            lifeExpectancy = 95
            currentBalance = 250000
            monthlyContribution = 2000
            realReturnRate = 0.05
            withdrawalRate = 0.04
            targetAnnualSpending = 60000
        }
    }
} | ConvertTo-Json -Depth 10

Invoke-RestMethod -Uri "http://localhost:3001/mcp" `
  -Method POST `
  -ContentType "application/json" `
  -Headers @{ Accept = "application/json, text/event-stream" } `
  -Body $payload
```

## Testing in MCP Hosts

### GitHub Copilot (Recommended for Development)

1. **Setup**: Register the MCP server in VS Code settings or GitHub Copilot configuration
2. **Verification**: Type `@nestpilot` in Copilot Chat to see available tools
3. **Testing**: Use natural language queries that match tool descriptions
4. **Debugging**: Check VS Code Output panel → "MCP" channel for errors

### Claude Desktop

1. **Setup**: Edit `claude_desktop_config.json` with server configuration
2. **Verification**: Ask "What NestPilot tools are available?"
3. **Testing**: Provide detailed retirement scenarios in conversation
4. **Debugging**: Check Claude Desktop logs: `%APPDATA%\Claude\logs\`

### MCPJam Inspector

```bash
npx @mcpjam/inspector@latest
```

1. Connect to `http://localhost:3001/mcp`
2. Browse available tools in the inspector UI
3. Test tools with custom JSON payloads
4. View real-time request/response

## Project Structure

```
apps/mcp-app/
├── server.ts                     # MCP server orchestrator
├── main.ts                       # Entry point: HTTP/stdio transport
├── nestpilot-client.ts           # HTTP client for NestPilot backend API
├── tools/
│   ├── mcp-helpers.ts            # Shared: toCallToolResult(), proxyPostTool()
│   ├── medicare-tools.ts         # Medicare tools (guardian, analyze, subscribe)
│   ├── planning-tools.ts         # Planning tools (create_plan, run_forecast, run_scenario, verify_forecast, coach)
│   ├── optimize-roth-tools.ts    # Roth conversion optimization (FEAT-0066) [IN DEVELOPMENT]
│   └── agent-tools.ts            # Agent runtime tools (list_skills, run_skill, run_plan)
├── mcp-app.html                  # Vite entry point for the Medicare Guardian view
├── src/
│   ├── planner/
│   │   └── planner-app.tsx       # Retirement planner interactive view
│   ├── mcp-app.tsx               # Medicare Guardian React app (useApp hook)
│   ├── types.ts                  # Shared TypeScript types
│   ├── styles.ts                 # CSS-in-JS styles with host variable fallbacks
│   ├── global.css                # Global CSS with host variable fallbacks
│   └── components/
│       ├── TimelineChecker.tsx   # Input form for user data
│       ├── ResultsPanel.tsx      # Results display (score, deadlines, penalties)
│       ├── EmailCapture.tsx      # Email subscription form
│       ├── CitationsDrawer.tsx   # Expandable citations section
│       ├── SEPInterview.tsx      # Special Enrollment Period checker
│       └── FunnelCTA.tsx         # Cross-sell to full NestPilot platform
├── tests/
│   ├── server.test.ts            # Server tool and client tests (vitest)
│   └── contract-policy.test.ts   # Contract validation tests
├── dist/                         # Build output (generated)
│   ├── mcp-app.html              # Bundled Medicare Guardian single-file HTML
│   ├── planner.html              # Bundled retirement planner single-file HTML
│   └── views/
│       └── verification-packet.html  # Bundled verification packet view
├── test-mcp-tools.mjs             # Comprehensive MCP tools test script
├── package.json
├── vite.config.ts
├── vite.planner.config.ts
├── vite.verification.config.ts
└──tsconfig.json
```

## Architecture

```
User in MCP Host (Claude / ChatGPT / GitHub Copilot / VS Code / MCPJam)
    |
    v
MCP Protocol (stdio or HTTP)
    |
    v
MCP Server (server.ts — orchestrator)
    |
    ├── tools/planning-tools.ts
    │   ├── create_plan          --> POST /api/plan/calc
    │   ├── run_forecast         --> POST /api/plan/forecast
    │   ├── run_scenario         --> POST /api/plan/scenario/run
    │   ├── verify_forecast      --> POST /api/plan/forecast/verify
    │   └── coach                --> POST /api/spring_ai/coach
    |
    ├── tools/roth-tools.ts
    │   └── optimize_roth_conversion  --> POST /api/tax/roth/max-conversion
    |
    ├── tools/medicare-tools.ts
    │   ├── medicare-guardian         --> renders UI resource (mcp-app.html)
    │   ├── medicare-analyze         --> POST /api/medicare/guardian/analyze
    │   └── email-subscribe          --> POST /api/medicare/subscribe
    |
    ├── tools/agent-tools.ts
    │   ├── nestpilot_list_skills    --> GET /skills (agent-runtime:3002)
    │   ├── nestpilot_run_skill      --> POST /sessions/:id/messages
    │   └── nestpilot_run_plan       --> POST /sessions/:id/messages
    |
    └── tools/mcp-helpers.ts
        ├── toCallToolResult()   -- wraps payload into MCP CallToolResult
        └── proxyPostTool()      -- POST to backend + error handling
                                        |
                                        v
                                NestPilot Spring Boot API (port 8080)
                                        |
                                        v
                                    PostgreSQL
```

Planning tools are thin facades — they validate input via Zod schemas and proxy to the Spring Boot API via `nestpilot-client.ts`. The Medicare Guardian view (React app in iframe) communicates with the server via `app.callServerTool()`.

## Environment Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `NESTPILOT_BACKEND_URL` | `http://localhost:8080` | NestPilot Spring Boot API URL |
| `AGENT_RUNTIME_URL` | `http://localhost:3002` | Agent Runtime service URL |
| `PORT` | `3001` | HTTP transport port |
| `MCP_REQUIRE_AUTH` | `true` | Require bearer authentication on HTTP `/mcp` |
| `MCP_AUTH_MODE` | `token` | Auth mode: `token` or `jwt-passthrough` |
| `MCP_AUTH_TOKENS` | (none) | Comma-separated bearer tokens (required in `token` mode when auth is enabled) |
| `MCP_DEFAULT_USER_ID` | `anonymous` | Fallback user id when auth is disabled |
| `MCP_RATE_LIMIT_WINDOW_MS` | `60000` | Rate limit window in milliseconds |
| `MCP_RATE_LIMIT_MAX_REQUESTS` | `60` | Max requests per window |

## Commands

```bash
npm run build                     # Vite build -> dist/*.html
npm run serve                     # Start MCP server (HTTP transport)
npm run serve:auth                # Start MCP server with auth validation + .env loading
npm run serve:auth:stdio          # Start stdio mode with auth env validation
npm run start                     # Build + serve
npm test                          # Run vitest tests
node test-mcp-tools.mjs           # Run comprehensive tool tests
```

## Known Issues

- **optimize_roth_conversion** tool (FEAT-0066) is currently under development and may not be fully functional
- Console.log output in tool registration appears suppressed in HTTP transport mode
- Tool registration happens per-request for HTTP transport, not at server startup

## Migration from chatgpt-app

| chatgpt-app (Python) | mcp-app (TypeScript) |
|----------------------|---------------------|
| `FastApps` / `WidgetMCPServer` | `McpServer` + `registerAppTool` |
| `BaseWidget` subclasses | `server.tool()` / `registerAppTool()` |
| `window.openai.callTool()` | `app.callServerTool()` |
| `useWidgetProps()` (FastApps) | `useApp()` (MCP Apps SDK) |
| `structuredContent` / `_meta` | `CallToolResult.content` |
| React JSX (JavaScript) | React TSX (TypeScript) |
| Python httpx | Node.js fetch |
| `fastapps.json` CSP | Single-file bundle (no CSP needed) |
|----------------------|---------------------|
| `FastApps` / `WidgetMCPServer` | `McpServer` + `registerAppTool` |
| `BaseWidget` subclasses | `server.tool()` / `registerAppTool()` |
| `window.openai.callTool()` | `app.callServerTool()` |
| `useWidgetProps()` (FastApps) | `useApp()` (MCP Apps SDK) |
| `structuredContent` / `_meta` | `CallToolResult.content` |
| React JSX (JavaScript) | React TSX (TypeScript) |
| Python httpx | Node.js fetch |
| `fastapps.json` CSP | Single-file bundle (no CSP needed) |