Skip to main content
Glama

Headline Vibes Analysis MCP Server

by fred-em
techContext.md5.91 kB
# Tech Context — Headline Vibes Last updated: 2025-08-21 ## Stack and Dependencies - Language: TypeScript (compiled to ESM JavaScript) - Runtime: Node.js v18+ (ESM) - MCP: @modelcontextprotocol/sdk 1.20 (stdio + HTTP transports) - HTTP: axios - NLP: chrono-node (natural language date parsing) - Sentiment: sentiment (lexicon-based) - Validation: zod + zod-to-json-schema - Logging: pino - Testing: vitest - Types: @types/node, @types/axios, @types/sentiment - Build: TypeScript compiler (tsc) package.json highlights: - type: "module" (ESM) - bin: headline-vibes -> build/index.mjs - scripts: - prebuild: mkdir -p build - build: tsc --pretty && chmod +x build/index.mjs - prepare: npm run build - watch: tsc --watch - start / start:stdio / start:http: runtime commands (env-driven transport) - test: vitest run ## Project Structure - src/index.mts - Entrypoint registering MCP tools, structured output, transports, health check - src/services/analysis.ts - Orchestrates fetching, filtering, scoring, and diagnostics - src/services/newsapi.ts - Configurable EventRegistry client - src/services/relevance.ts & constants/relevance.ts - Investor relevance lexicon helpers - src/services/summaries.ts - Synopsis builders for general/investor sentiment - src/logger.ts - Pino logger - build/ - Compiled output (index.mjs, .d.ts) - tsconfig.json - TypeScript configuration targeting ESM build - README.md - Usage, setup, and examples ## Environment and Configuration - Required env: - NEWS_API_KEY: EventRegistry API key (asserted at startup) - Optional env: - NEWS_API_BASE_URL (defaults to https://eventregistry.org/api/v1/) - TRANSPORT (stdio|http), HOST, PORT - LOG_LEVEL, ALLOWED_HOSTS, ALLOWED_ORIGINS - RATE_LIMIT_DAILY_REQUESTS, RATE_LIMIT_PER_SECOND - BACKFILL_PAGE_CAP_PER_DAY, BACKFILL_MODE - BUDGET_MONTHLY_TOKENS, BUDGET_SOFT_CAP_PCT, BUDGET_HARD_CAP_PCT, ALLOW_OVERAGE - Axios client: - baseURL: NEWS_API_BASE_URL - Authentication: `apiKey` query param (EventRegistry requirement) ## MCP Integration Example MCP client configuration: ```jsonc { "mcpServers": { "headline-vibes": { "command": "node", "args": ["/absolute/path/to/headline-vibes/build/index.mjs"], "env": { "NEWS_API_KEY": "your-eventregistry-key", "TRANSPORT": "stdio" } } } } ``` Server details: - Transports: - stdio via `StdioServerTransport` - HTTP via `StreamableHTTPServerTransport` behind Node `createServer` with `/healthz` - ListTools returns analyze_headlines + analyze_monthly_headlines with schemas - CallTool responses: - `content`: human-readable summary - `structuredContent`: JSON matching Zod schemas ## Tools (Schemas) Schemas defined in `src/schemas/headlines.ts`, exported to JSON via zod-to-json-schema. 1) analyze_headlines - input: { input: string } (natural language or YYYY-MM-DD) - structuredContent: AnalyzeHeadlinesSchema (scores, distributions, diagnostics) - Errors: - InvalidParams if missing/unparseable date - ResourceExhausted if token budget exceeded - InternalError on EventRegistry failures 2) analyze_monthly_headlines - input: { startMonth: YYYY-MM, endMonth: YYYY-MM } - structuredContent: AnalyzeMonthlySchema (per-month sentiments + diagnostics) - Errors: - InvalidParams if month format invalid - ResourceExhausted per-month when token budget blocks a fetch - InternalError when EventRegistry fails for a month (captured per result) ## External API Usage - Endpoint: POST `https://eventregistry.org/api/v1/article/getArticles` - Query params: `apiKey` - Body fields: resultType=articles, dateStart/dateEnd, lang, articlesPage, articlesCount=100, articlesSortBy=date - Optional: sourceUri[] (resolved via SourceResolver) - Pagination: - pageSize=100 (EventRegistry max) - Iterate until < pageSize or configured `pageCap` - Request counts recorded for budgeting diagnostics ## Key Computation Patterns - Relevance filter: - exclusion terms short-circuit relevance - inclusion weights (>0) mark investor relevance; matched terms saved for diagnostics - General sentiment: - sentiment(text).comparative average - normalized from [-1, 1] to [0, 10] - Investor sentiment: - Weighted term hits (custom lexicon) - normalized from [-4, 4] to [0, 10] - Political categorization: - SOURCE_CATEGORIZATION constant by kebab-case source ids - Fallback to center when unknown - Balanced selection (daily): - After filtering, distribute evenly per source before truncation ## Development Workflow - Install: `npm install` - Build: `npm run build` - Watch: `npm run watch` - Tests: `npm test` (vitest) - Local stdio run: `NEWS_API_KEY=... npm run start:stdio` - Local HTTP run: `TRANSPORT=http HOST=0.0.0.0 PORT=8787 NEWS_API_KEY=... npm run start:http` - Smoke check: `node ./build/scripts/smoke.mjs <date>` - Logging via pino; level controlled by `LOG_LEVEL` ## Error Handling - McpError with ErrorCode: - InvalidParams for input validation issues (dates, formats) - ResourceExhausted for token budget or rate-limit exhaustion - InternalError for EventRegistry failures or unexpected errors - Process signals: - SIGINT: closes server cleanly - Server.onerror: logs MCP errors ## Technical Constraints and Considerations - ESM-only (type: module); imports must include file extensions (.js) - Requires NEWS_API_KEY at runtime (asserted at boot) - Token budgeting enforced via `services/tokenBudget.ts` - Source URIs resolved via `sourceResolver` cache; uncategorized defaults to center - No runtime persistence (documentation-only memory) ## Potential Enhancements - Caching layer keyed by query inputs with TTL and invalidation - Externalized configuration (lexicons, mappings) with hot-reload - CLI flags/env for caps (maxHeadlines) and sources - Tests for date parsing, filtering, normalization, and categorization

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/fred-em/headline-vibes'

If you have feedback or need assistance with the MCP directory API, please join our Discord server