# Research & Technical Decisions
**Feature**: HackerNews MCP Server
**Date**: October 12, 2025
**Status**: Complete
## Overview
This document captures all technical research and decisions made during Phase 0 of the implementation planning process. All "NEEDS CLARIFICATION" items from the Technical Context have been resolved through research using Context7 MCP.
## Technology Stack Decisions
### 1. Programming Language & Runtime
**Decision**: Node.js with TypeScript (strict mode)
**Rationale**:
- MCP TypeScript SDK (`@modelcontextprotocol/sdk`) provides comprehensive, well-documented support for building MCP servers
- TypeScript strict mode enables compile-time type safety, catching errors early
- Node.js provides excellent HTTP client libraries for consuming the HackerNews API
- Large ecosystem of testing tools (Vitest, Jest) and type-safe HTTP clients
- Strong community support and extensive examples in the MCP repository
**Alternatives Considered**:
- **Python SDK**: Good support but TypeScript offers better IDE integration and type safety for this use case
- **Kotlin/Java**: More verbose, less common for MCP servers, smaller ecosystem
- **Go**: Would require manual protocol implementation, no official SDK
**Source**: MCP TypeScript SDK documentation via Context7 (`/modelcontextprotocol/typescript-sdk`)
---
### 2. MCP Transport Protocol
**Decision**: stdio (Standard Input/Output)
**Rationale**:
- stdio is the recommended transport for local MCP servers that are spawned as child processes
- Simpler setup than HTTP/SSE for end users (no port management, no network configuration)
- Better security model (no exposed network ports)
- Matches the user requirement: "Use stdio protocol"
- MCP SDK provides `StdioServerTransport` class with full support
- Standard pattern in MCP ecosystem for tool-based servers
**Example from Research**:
```typescript
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
const transport = new StdioServerTransport();
await server.connect(transport);
```
**Alternatives Considered**:
- **HTTP with Streamable HTTP**: Better for web-based deployments but adds complexity for local usage
- **SSE (Server-Sent Events)**: Deprecated in favor of Streamable HTTP, not recommended for new projects
**Source**: MCP TypeScript SDK examples showing stdio as primary local transport pattern
---
### 3. Code Quality & Formatting
**Decision**: Biome for linting and formatting
**Rationale**:
- User explicitly requested: "Use biome for linting & formatting"
- Biome is a fast, all-in-one toolchain replacing ESLint + Prettier
- Zero configuration conflicts (single tool for both linting and formatting)
- 10-100x faster than Prettier for large codebases
- Native TypeScript support with built-in rules for correctness and style
- Growing ecosystem with strong community support
**Configuration Approach**:
```json
{
"$schema": "https://biomejs.dev/schemas/1.0.0/schema.json",
"formatter": {
"enabled": true,
"indentStyle": "tab",
"lineWidth": 100
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"correctness": { "noUnusedVariables": "error" },
"style": { "noVar": "error", "useConst": "warn" }
}
},
"javascript": {
"formatter": {
"quoteStyle": "double",
"trailingCommas": "es5"
}
}
}
```
**Alternatives Considered**:
- **ESLint + Prettier**: Traditional approach but slower and requires managing two tools
- **Deno fmt + lint**: Only works with Deno runtime, not compatible with Node.js
**Source**: Biome documentation via Context7 (`/biomejs/biome`)
---
### 4. Testing Framework
**Decision**: Vitest with separate unit, integration, and contract tests
**Rationale**:
- Vitest is Vite-native and extremely fast (built on esbuild)
- First-class TypeScript support without additional configuration
- Jest-compatible API (easy migration path if needed)
- Built-in coverage reporting with c8/istanbul
- Excellent watch mode for TDD workflow
- Supports ESM modules natively (important for MCP SDK)
**Test Structure**:
```
tests/
├── unit/ # Pure function tests, no I/O
├── integration/ # Tests with real HackerNews API calls
└── contract/ # MCP protocol compliance tests
```
**Alternatives Considered**:
- **Jest**: Slower, requires more configuration for ESM
- **Node:test**: Built-in but lacks maturity and ecosystem
- **Mocha + Chai**: Requires more setup, less modern
**Coverage Requirements** (per Constitution):
- Minimum 80% coverage overall
- 100% coverage for critical paths (API request/response handling)
---
### 5. HTTP Client for HackerNews API
**Decision**: Native `fetch` API (Node.js 18+)
**Rationale**:
- Native to Node.js 18+ (no external dependencies)
- Standard web API (same interface as browser fetch)
- Built-in TypeScript types
- Promise-based, async/await friendly
- Sufficient for HackerNews API needs (simple GET requests)
- Reduces dependency footprint (aligns with Constitution Principle V)
**Example Usage**:
```typescript
const response = await fetch('https://hn.algolia.com/api/v1/search?query=AI');
const data = await response.json();
```
**Alternatives Considered**:
- **axios**: Popular but adds 450KB+ of dependencies, unnecessary for simple GET requests
- **got**: Powerful but heavyweight, better for complex scenarios
- **node-fetch**: No longer needed with Node 18+ built-in fetch
**Dependency Minimization**: Using native fetch eliminates an entire dependency category
---
### 6. Schema Validation
**Decision**: Zod for runtime schema validation
**Rationale**:
- MCP SDK uses Zod extensively for tool input/output schemas
- TypeScript-first design provides excellent type inference
- Composable schema definitions with clear error messages
- Small bundle size (~8KB minified + gzipped)
- Active development and strong community
- Built-in validation for API responses and tool inputs
**Example from MCP SDK**:
```typescript
server.registerTool(
'search-posts',
{
inputSchema: {
query: z.string().min(1),
tags: z.array(z.string()).optional(),
page: z.number().int().min(0).default(0)
},
outputSchema: {
hits: z.array(z.any()),
nbHits: z.number()
}
},
async (params) => { /* handler */ }
);
```
**Alternatives Considered**:
- **io-ts**: More functional but steeper learning curve
- **Yup**: Object-oriented but less TypeScript-native
- **JSON Schema**: Verbose, less ergonomic for TypeScript
**Source**: MCP SDK examples showing Zod as standard for schema definition
---
### 7. Project Structure
**Decision**: Modular tool-based structure with separate files per tool
**Rationale**:
- User requirement: "structured the app so tool calls are separated by file"
- Promotes single responsibility principle (Constitution I)
- Easier testing (each tool can be tested in isolation)
- Better code organization and maintainability
- Follows MCP best practices from examples
**Structure**:
```
src/
├── index.ts # Main entry point, server setup
├── tools/ # MCP tool implementations
│ ├── search-posts.ts # Search tool
│ ├── get-front-page.ts # Front page tool
│ ├── get-latest-posts.ts # Latest posts tool
│ ├── get-item.ts # Item retrieval tool
│ └── get-user.ts # User profile tool
├── services/ # Business logic
│ └── hn-api.ts # HackerNews API client
├── types/ # TypeScript type definitions
│ ├── hn-types.ts # HackerNews API response types
│ └── mcp-types.ts # MCP-specific types
└── utils/ # Shared utilities
├── validators.ts # Input validation helpers
└── error-handlers.ts # Error handling utilities
```
**Benefits**:
- Clear separation of concerns
- Easy to locate and modify specific tools
- Supports incremental development (build one tool at a time)
- Facilitates parallel development by multiple contributors
---
### 8. Error Handling Strategy
**Decision**: Structured error handling with typed error responses
**Rationale**:
- MCP protocol supports `isError` flag in tool responses
- TypeScript enables type-safe error handling
- Clear error messages improve user experience (Constitution III)
- All errors must be explicitly handled (Constitution I)
**Pattern**:
```typescript
try {
const response = await fetch(url);
if (!response.ok) {
return {
content: [{ type: 'text', text: `API error: ${response.statusText}` }],
isError: true
};
}
// ... process response
} catch (error) {
return {
content: [{ type: 'text', text: `Network error: ${error.message}` }],
isError: true
};
}
```
---
### 9. Rate Limiting Strategy
**Decision**: Informational warnings, no automatic throttling
**Rationale**:
- HackerNews API rate limit: 10,000 requests/hour per IP
- For typical MCP usage, this limit is unlikely to be hit
- Adding throttling adds complexity without clear benefit
- Better to fail fast with clear error messages
- Can be added later if usage patterns warrant it
**Implementation**:
- Document rate limits clearly in README
- Return helpful error messages when 429 status received
- Include rate limit info in tool descriptions
---
### 10. Documentation Approach
**Decision**: Multi-tier documentation for different audiences
**Rationale**:
- User requirement: "create a user-facing readme and documentation suitable for open source distribution and collaboration"
- Constitution Principle IV: Documentation-First Development
**Documentation Structure**:
1. **README.md**: Quick start, installation, basic usage examples
2. **docs/API.md**: Detailed API reference for all tools
3. **docs/CONTRIBUTING.md**: Development setup, testing, contribution guidelines
4. **docs/ARCHITECTURE.md**: System design, component interactions
5. **Inline JSDoc**: For all public functions and types
**Target Audiences**:
- **End Users**: README with installation and usage
- **Contributors**: CONTRIBUTING and ARCHITECTURE docs
- **API Consumers**: Tool descriptions in MCP tool definitions
- **Developers**: JSDoc comments and type definitions
---
## Best Practices from MCP Examples
### 1. Tool Registration Pattern
Based on official MCP examples, tools should:
- Use clear, descriptive names (e.g., `search-posts`, not `search`)
- Provide comprehensive descriptions for LLM understanding
- Define precise input/output schemas with Zod
- Return both `content` (for display) and `structuredContent` (for parsing)
### 2. Resource vs Tool Decision
**Decision**: Use Tools only, no Resources
**Rationale**:
- HackerNews API is query-based (requires parameters)
- Resources are for static or addressable content (e.g., `file://`, `config://`)
- Tools are appropriate for API operations with inputs
- Simpler mental model for users
### 3. Prompts
**Decision**: No custom prompts initially
**Rationale**:
- Prompts are useful for pre-defined queries or templates
- HackerNews queries are too variable to template effectively
- Can be added in future if common patterns emerge
- Focus on core functionality first
---
## Performance Targets
Based on success criteria from spec.md:
| Operation | Target | Rationale |
|-----------|--------|-----------|
| Search queries | < 2 seconds | Matches user expectation (SC-001) |
| Front page retrieval | < 2 seconds | Simple API call, should be fast |
| Item retrieval | < 3 seconds | May need nested comments (SC-003) |
| User profile | < 1 second | Simple API endpoint (SC-004) |
**Implementation Notes**:
- No client-side caching initially (per out-of-scope)
- Performance primarily depends on HackerNews API response times
- Connection reuse via keep-alive headers
- Timeouts set to 5 seconds to fail fast
---
## Security Considerations
1. **No Authentication Required**: HackerNews API is public and read-only
2. **Input Validation**: All user inputs validated with Zod schemas
3. **Error Message Safety**: Never expose internal stack traces to users
4. **Dependency Security**: Regular security audits with `npm audit`
5. **Rate Limiting**: Respect API limits, clear error messages on violations
---
## Development Workflow
**Test-First Development** (Constitution Principle II):
1. Write failing test for tool behavior
2. Implement minimum code to pass test
3. Refactor with tests passing
4. Repeat for next feature
**Git Workflow**:
- Feature branch: `001-hackernews-mcp-server`
- Commit convention: `type(scope): description`
- PR reviews required before merge
---
## Open Questions & Future Considerations
### Potential Enhancements (Not in MVP):
1. **Caching Layer**: Could add in-memory cache for frequently accessed items
2. **Batch Operations**: Could support fetching multiple items in one call
3. **Subscription Support**: Real-time updates for front page changes
4. **Advanced Filtering**: Client-side filtering beyond API capabilities
### Monitoring Considerations:
- Request success/failure metrics
- Response time tracking
- Error rate monitoring
- Usage patterns analysis
These are explicitly out of scope for initial implementation but documented for future reference.
---
## Summary
All technical unknowns have been resolved:
✅ **Language/Runtime**: Node.js + TypeScript (strict mode)
✅ **Transport**: stdio protocol via `StdioServerTransport`
✅ **Testing**: Vitest with 80%+ coverage target
✅ **Linting/Formatting**: Biome (per user request)
✅ **HTTP Client**: Native fetch API (Node 18+)
✅ **Validation**: Zod schemas (MCP standard)
✅ **Structure**: Modular tool-per-file organization
✅ **Error Handling**: Typed errors with MCP `isError` flag
✅ **Documentation**: Multi-tier for different audiences
**Next Phase**: Design data models and API contracts based on these decisions.