# askme-server CLAUDE.md
## stdio Server Implementation
The Ask-Me MCP server uses stdio transport for direct integration with Claude Code and other MCP clients.
### Running the Server
```bash
# Build and serve with Nx
npx nx serve askme-server
# Or run directly after building
node dist/askme-server/main.js
# For npm package testing
npx ask-me-mcp
# With debug logging enabled
ASK_ME_MCP_DEBUG=1 npx ask-me-mcp
```
### Port Behavior (Updated)
The server now has two distinct port behaviors:
1. **Auto-discovery (default)**: When no `--port` specified, finds available port starting from 3000
2. **Fixed port**: When `--port` specified, uses exact port and fails if occupied
```bash
# Auto-discovery (flexible)
npx ask-me-mcp
# Fixed port (precise control)
npx ask-me-mcp --port 8080
```
### Modular Architecture (Restructured)
The server follows MCP server patterns with a clean modular structure:
```
askme-server/src/
├── main.ts # Minimal entry point
├── core/ # Core server functionality
│ ├── server.ts # MCP server setup & tool registration
│ ├── browser-bridge.ts # HTTP/SSE communication with browser
│ ├── request-manager.ts # Request lifecycle management
│ └── index.ts # Core module exports
├── tools/ # Individual tool implementations
│ ├── ask-one-question.tool.ts # Single question tool
│ ├── ask-multiple-choice.tool.ts # Multiple choice tool
│ └── index.ts # Tool exports & registry
└── prompts/ # MCP prompt implementations
├── human-decision.prompt.ts # Human decision-making prompt
├── expert-consultation.prompt.ts # Expert guidance prompt
├── creative-brainstorm.prompt.ts # Creative ideation prompt
├── suggest-follow-up-questions.prompt.ts # Follow-up question generation
└── index.ts # Prompt exports & registry
```
#### Key Components:
- **Transport**: Uses `StdioServerTransport` for stdin/stdout communication
- **MCP SDK**: Implements the Model Context Protocol using `@modelcontextprotocol/sdk`
- **Request Management**: `RequestManager` class with Map-based storage for pending requests
- **Browser Bridge**: Embedded minimal HTTP server with dynamic/fixed port allocation
- **Static UI Serving**: Serves Angular UI directly from server (bundled in npm package)
- **Tool Registration**: Centralized tool registration with clean separation of concerns
- **Prompt Support**: MCP prompts for template-based human guidance and question generation
- **Automatic UI**: Cross-platform browser opening when no UI is connected, with fallback instructions
- **Debug Logging**: All console output conditional on `ASK_ME_MCP_DEBUG` environment variable
#### Benefits of Modular Structure:
- Each tool is in its own file for easier maintenance
- Core services are separated for better testability
- Easy to add new tools by creating new files in tools/ directory
- Follows established patterns from official MCP servers
- Clean imports and proper TypeScript typing
### Browser Bridge Endpoints
The stdio server includes a minimal HTTP server for browser UI communication:
- **GET /mcp/browser-events**: SSE endpoint for real-time updates
- No session ID required (simplified single-request model)
- Sends proper SSE formatted messages
- Includes heartbeat every 30 seconds
- Used to detect UI connection status for automatic browser opening
- **POST /mcp/response**: Receives human responses from the UI
- **GET /**: Serves Angular UI (index.html and static assets)
- **GET /any-route**: Angular SPA routing (serves index.html for client-side routing)
### Static File Serving (New Feature)
The server now serves the Angular UI statically:
- **Angular Build Path**: Automatically detects `dist/askme-ui/browser/` in various deployment scenarios
- **SPA Routing**: Serves `index.html` for unmatched routes (Angular routing)
- **MIME Types**: Proper content-type headers for .js, .css, .html, .png, etc.
- **Bundled in npm**: Angular build is included in the published npm package
### Automatic Browser Opening Feature
When the server receives a request from an MCP client and detects no UI is running:
1. **UI Detection**: Checks `sseConnections.size` to determine if browser UI is connected
2. **Cross-Platform Opening**: Uses platform-specific commands with dynamic port:
- **macOS**: `open "http://localhost:{actualPort}"`
- **Windows**: `start "" "http://localhost:{actualPort}"`
- **Linux**: `xdg-open "http://localhost:{actualPort}"`
3. **Fallback Instructions**: If browser opening fails, returns detailed manual setup instructions
4. **Integration**: All tools call `ensureUIAvailable()` before processing requests
**Implementation Location**: `core/browser-bridge.ts` - `ensureUIAvailable()` function
### Request Management
- Uses simple Map for pending request storage with promise-based resolution
- No sessions or queues - direct request/response model
- Each request gets a unique ID and awaits human response
- 5-minute timeout per request to prevent indefinite waiting
### Testing the Tools
From Claude Code or any MCP client connected via stdio:
#### ask-one-question Tool
```
ask-one-question "What is your favorite color?"
```
**Note**: Questions should be written in markdown format with proper formatting (headers, lists, code blocks, etc.) to make them clear and readable for humans.
#### ask-multiple-choice Tool
```
ask-multiple-choice {
"questions": [
{
"text": "Which deployment environments should we use?",
"options": ["Development", "Staging", "Production"]
},
{
"text": "Which features are ready for release?",
"options": ["User Auth", "Dashboard", "Reports", "API v2"]
}
]
}
```
#### challenge-hypothesis Tool
```
challenge-hypothesis {
"title": "Market Analysis Hypotheses",
"description": "Please evaluate these market predictions for Q4",
"hypotheses": [
"Our product will gain 15% market share by end of Q4",
"Competitor X will launch a similar product within 3 months",
"Customer satisfaction will improve by 25% with new features"
]
}
```
#### choose-next Tool
```
choose-next {
"title": "Choose Development Priority",
"description": "# Next Development Phase\n\nWe need to decide which feature to develop next.",
"options": [
{
"id": "auth",
"title": "User Authentication",
"description": "Implement secure user login and registration system",
"icon": "🔐"
},
{
"id": "dashboard",
"title": "Analytics Dashboard",
"description": "Create comprehensive data visualization tools",
"icon": "📊"
}
]
}
```
The requests will appear in the web UI at http://localhost:4200 and block until a human responds.
- **Multiple choice questions**: Users can select multiple options and add comments to each choice
- **New Feature**: Completion status buttons allow users to guide client behavior:
- "Submit and I am done with Answering" → Server responds with instructions to stop asking questions
- "Submit, drill deeper by asking more" → Server responds with instructions to ask follow-up questions
- **Hypothesis challenges**: Users evaluate each hypothesis on a 7-step agreement scale (😤 Fully Disagree to 😍 Fully Agree) with optional comments
- **Choose-next decisions**: Users see options in animated, clickable boxes and can:
- Select a preferred option with optional message
- Abort (reject all options)
- Request new/alternative ideas
### Response Processing Features
#### Multiple Choice Completion Status
The `ask-multiple-choice` tool now processes an optional `completionStatus` field in responses:
- **'done'**: Server includes instruction: "Do not ask additional questions. Proceed with implementation based on the answers provided."
- **'drill-deeper'**: Server includes instruction: "Ask follow-up questions to get more detailed information. Use ask-one-question for open-ended follow-ups or ask-multiple-choice for more structured options."
This feature allows humans to explicitly guide the MCP client's next actions, improving the human-in-the-loop workflow efficiency.
## MCP Client Abort/Cancellation Handling
### Overview
When MCP clients abort requests (e.g., pressing ESC in Claude Code), the server now detects this via the MCP SDK's built-in `AbortSignal` mechanism and properly cleans up stale requests in the browser UI.
### Implementation Details
#### Server-Side Abort Detection
All tool handlers now accept an `extra?: { signal?: AbortSignal }` parameter:
```typescript
export async function handleAskOneQuestion(
args: AskOneQuestionArgs,
requestStorage: Map<string, any>,
notifyBrowser: (message: any) => void,
extra?: { signal?: AbortSignal } // ← Added for abort detection
): Promise<any>
```
#### Abort Detection Pattern
1. **Early Detection**: Check if request was already cancelled before processing
```typescript
if (extra?.signal?.aborted) {
throw new McpError(ErrorCode.InvalidRequest, 'Request was cancelled');
}
```
2. **Runtime Detection**: Listen for abort events during request lifecycle
```typescript
const abortListener = () => {
// Clean up request storage
requestStorage.delete(requestId);
// Notify browser of cancellation
notifyBrowser({ type: 'request_cancelled', data: { requestId, message } });
// Reject promise
reject(new McpError(ErrorCode.InvalidRequest, 'Request was cancelled by client'));
};
extra?.signal?.addEventListener('abort', abortListener);
```
3. **Cleanup**: Properly remove event listeners in timeout handlers and response handlers
#### Browser Notification Messages
- **Timeout**: `{ type: 'request_timeout', data: { requestId, message } }`
- **Cancellation**: `{ type: 'request_cancelled', data: { requestId, message } }`
### MCP Protocol Integration
- Uses native `AbortSignal` from `@modelcontextprotocol/sdk`
- Responds to `notifications/cancelled` protocol messages
- Server request handler receives `extra` parameter: `server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {...})`
### Error Code Usage
Use `ErrorCode.InvalidRequest` for cancellation errors since `ErrorCode.Cancelled` doesn't exist in the MCP SDK.
## MCP Prompts
The Ask-Me MCP server also provides **prompts** - reusable, parameterized text templates that clients can invoke for consistent question formatting and response guidance.
### Available Prompts
#### suggest-follow-up-questions Prompt
Generates intelligent follow-up questions based on human responses to maintain effective conversation flow.
```typescript
// Usage in MCP client
const prompt = await client.getPrompt('suggest-follow-up-questions', {
originalQuestion: "What features should we prioritize for the next release?",
response: "User authentication and dashboard improvements are most important",
goal: "Create a product roadmap", // optional
responseType: "open" // optional: 'open', 'multiple-choice', 'hypothesis'
});
```
**Parameters:**
- `originalQuestion` (required): The initial question that was asked
- `response` (required): The human response that was received
- `goal` (optional): The ultimate objective or purpose of the questioning
- `responseType` (optional): Type of response received (open, multiple-choice, hypothesis)
**Output:** Structured analysis with 3-5 prioritized follow-up questions, each including:
- Question text formatted for the appropriate response type
- Priority level (High/Medium/Low)
- Reasoning for importance
- Suggested question type (open-ended, multiple-choice, hypothesis)
- Analysis summary of what additional information would be valuable
#### human-decision Prompt
Requests human judgment and decision-making for complex scenarios where automated systems need guidance.
```typescript
const prompt = await client.getPrompt('human-decision', {
context: "Should we deploy the new feature to production?",
options: "1. Deploy immediately 2. Wait for more testing 3. Deploy to staging first",
urgency: "high", // optional: 'low', 'medium', 'high'
domain: "technical" // optional
});
```
#### expert-consultation Prompt
Seeks domain-specific expert guidance and recommendations.
```typescript
const prompt = await client.getPrompt('expert-consultation', {
topic: "Cloud architecture optimization",
expertise_area: "DevOps Engineering",
specific_question: "How to improve deployment pipeline efficiency?", // optional
background_info: "Current pipeline takes 45 minutes", // optional
expected_outcome: "Concrete optimization recommendations" // optional
});
```
#### creative-brainstorm Prompt
Facilitates creative problem-solving and ideation sessions.
```typescript
const prompt = await client.getPrompt('creative-brainstorm', {
challenge: "Design a new mobile app onboarding experience",
goal: "Reduce user drop-off rate", // optional
constraints: "Mobile-first, under 3 minutes", // optional
target_audience: "Tech-savvy millennials", // optional
inspiration_sources: "Gaming apps, social media", // optional
idea_count: 7 // optional, default: 7
});
```
### Prompt Integration Benefits
- **Consistency**: Standardized question formatting across different contexts
- **Guidance**: Template-based approach ensures comprehensive coverage of important aspects
- **Efficiency**: Pre-structured prompts save time and improve question quality
- **Workflow Enhancement**: `suggest-follow-up-questions` maintains conversation flow in human-in-the-loop scenarios
- **Domain Expertise**: Specialized prompts for different types of human input (decisions, expertise, creativity)