# rmouahid/novit architecture

> Architecture diagram of the GitHub repository rmouahid/novit, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-11-11). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/rmouahid/novit
- Repository: https://github.com/rmouahid/novit

## Overview

NovIT is an MCP server that collects technology-news articles, classifies and stores them, then serves profile-aware news and related tools to MCP clients. The documented principal workflow is client → MCP tools → handlers → cache or collection → article storage → formatted results. Additional branches cover search and analysis, user preferences and feedback, and stdio/optional HTTP transport. Source excerpts support the main handler, scraper-manager and storage interactions; other capabilities and links are included only where the README or source index documents them.

Main entry points: [`novit/mcp/handlers.py`](https://github.com/rmouahid/novit/blob/main/novit/mcp/handlers.py) (Tool handlers), [`novit/scrapers/storage.py`](https://github.com/rmouahid/novit/blob/main/novit/scrapers/storage.py) (Article store), [`novit/mcp/server.py`](https://github.com/rmouahid/novit/blob/main/novit/mcp/server.py) (MCP server), [`novit/scrapers/manager.py`](https://github.com/rmouahid/novit/blob/main/novit/scrapers/manager.py) (Scraper manager)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_mcp["MCP interface"]
  node_server["MCP server<br/>[server.py]"]
  node_handlers["Tool handlers<br/>[handlers.py]"]
  node_schemas["Tool schemas<br/>[schemas.py]"]
  node_http_transport["HTTP transport<br/>[http.py]"]
  node_cache["TTL cache<br/>[cache.py]"]
end

subgraph group_scraping["Collection"]
  node_manager["Scraper manager<br/>[manager.py]"]
  node_sources["Source scrapers"]
  node_http_client["Polite HTTP client<br/>[http.py]"]
end

subgraph group_articles["Article processing"]
  node_article_model["Article model<br/>[base.py]"]
  node_tagger["Domain tagger<br/>[tagger.py]"]
  node_dedupe["Deduplication<br/>[deduplication.py]"]
  node_storage[("Article store<br/>[storage.py]")]
  node_offline["Offline fallback<br/>[offline.py]"]
  node_settings["Runtime settings<br/>[settings.py]"]
end

subgraph group_personalization["User context"]
  node_profile["Profiles<br/>[profile.py]"]
  node_filter["Profile ranking<br/>[filter.py]"]
  node_preferences[("User preferences<br/>[preferences.py]")]
  node_users["User context<br/>[users.py]"]
  node_sessions["Sessions<br/>[session.py]"]
end

subgraph group_analysis["Insights and feedback"]
  node_daily["Daily summary<br/>[daily.py]"]
  node_trends["Trend analysis<br/>[trends.py]"]
  node_related["Related articles<br/>[related.py]"]
  node_unusual["Unusual articles<br/>[unusual.py]"]
  node_feedback[("User feedback<br/>[feedback.py]")]
  node_health["Health checks<br/>[health.py]"]
end

node_client(("MCP client"))
node_external_sources(("News sources"))

node_client -->|"calls tools"| node_server
node_server -->|"dispatches tools"| node_handlers
node_server -->|"declares contracts"| node_schemas
node_server -.->|"serves optionally"| node_http_transport
node_handlers -->|"checks cache"| node_cache
node_handlers -->|"reads and saves"| node_storage
node_handlers -->|"starts collection"| node_manager
node_handlers -->|"tags collected"| node_tagger
node_handlers -->|"falls back"| node_offline
node_handlers -->|"selects profile"| node_profile
node_handlers -->|"ranks articles"| node_filter
node_manager -->|"runs in parallel"| node_sources
node_manager -->|"deduplicates results"| node_dedupe
node_sources -->|"fetches through"| node_http_client
node_http_client -->|"requests articles"| node_external_sources
node_sources -->|"produces articles"| node_article_model
node_manager -->|"aggregates articles"| node_article_model
node_tagger -->|"annotates articles"| node_article_model
node_storage -->|"stores articles"| node_article_model
node_settings -->|"configures requests"| node_http_client
node_settings -.->|"configures database"| node_storage
node_profile -->|"loads configuration"| node_settings
node_filter -->|"uses weights"| node_profile
node_handlers -->|"builds summaries"| node_daily
node_handlers -->|"dispatches analysis"| node_trends
node_handlers -.->|"dispatches lookup"| node_related
node_handlers -->|"dispatches lookup"| node_unusual
node_handlers -.->|"records feedback"| node_feedback
node_handlers -.->|"serves health"| node_health
node_feedback -.->|"captures context"| node_users
node_preferences -->|"scopes preferences"| node_users
node_sessions -->|"scopes sessions"| node_users
node_trends -->|"reads articles"| node_storage
node_related -->|"reads articles"| node_storage
node_unusual -->|"reads articles"| node_storage

click node_server "https://github.com/rmouahid/novit/blob/main/novit/mcp/server.py"
click node_handlers "https://github.com/rmouahid/novit/blob/main/novit/mcp/handlers.py"
click node_schemas "https://github.com/rmouahid/novit/blob/main/novit/mcp/schemas.py"
click node_http_transport "https://github.com/rmouahid/novit/blob/main/novit/mcp/http.py"
click node_cache "https://github.com/rmouahid/novit/blob/main/novit/mcp/cache.py"
click node_manager "https://github.com/rmouahid/novit/blob/main/novit/scrapers/manager.py"
click node_http_client "https://github.com/rmouahid/novit/blob/main/novit/scrapers/http.py"
click node_article_model "https://github.com/rmouahid/novit/blob/main/novit/scrapers/base.py"
click node_tagger "https://github.com/rmouahid/novit/blob/main/novit/scrapers/tagger.py"
click node_dedupe "https://github.com/rmouahid/novit/blob/main/novit/scrapers/deduplication.py"
click node_storage "https://github.com/rmouahid/novit/blob/main/novit/scrapers/storage.py"
click node_offline "https://github.com/rmouahid/novit/blob/main/novit/mcp/offline.py"
click node_settings "https://github.com/rmouahid/novit/blob/main/novit/settings.py"
click node_profile "https://github.com/rmouahid/novit/blob/main/novit/profiles/profile.py"
click node_filter "https://github.com/rmouahid/novit/blob/main/novit/profiles/filter.py"
click node_preferences "https://github.com/rmouahid/novit/blob/main/novit/profiles/preferences.py"
click node_users "https://github.com/rmouahid/novit/blob/main/novit/mcp/users.py"
click node_sessions "https://github.com/rmouahid/novit/blob/main/novit/mcp/session.py"
click node_daily "https://github.com/rmouahid/novit/blob/main/novit/mcp/daily.py"
click node_trends "https://github.com/rmouahid/novit/blob/main/novit/mcp/trends.py"
click node_related "https://github.com/rmouahid/novit/blob/main/novit/mcp/related.py"
click node_unusual "https://github.com/rmouahid/novit/blob/main/novit/mcp/unusual.py"
click node_feedback "https://github.com/rmouahid/novit/blob/main/novit/mcp/feedback.py"
click node_health "https://github.com/rmouahid/novit/blob/main/novit/mcp/health.py"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_server,node_handlers,node_schemas,node_http_transport,node_cache,node_client toneBlue
class node_manager,node_sources,node_http_client toneAmber
class node_article_model,node_tagger,node_dedupe,node_storage,node_offline,node_settings toneMint
class node_profile,node_filter,node_preferences,node_users,node_sessions toneRose
class node_daily,node_trends,node_related,node_unusual,node_feedback,node_health,node_external_sources toneIndigo
```

## Components

### MCP interface

- [MCP server](https://github.com/rmouahid/novit/blob/main/novit/mcp/server.py): `novit/mcp/server.py`
- [Tool handlers](https://github.com/rmouahid/novit/blob/main/novit/mcp/handlers.py): `novit/mcp/handlers.py`
- [Tool schemas](https://github.com/rmouahid/novit/blob/main/novit/mcp/schemas.py): `novit/mcp/schemas.py`
- [HTTP transport](https://github.com/rmouahid/novit/blob/main/novit/mcp/http.py): `novit/mcp/http.py`
- [TTL cache](https://github.com/rmouahid/novit/blob/main/novit/mcp/cache.py): `novit/mcp/cache.py`

### Collection

- [Scraper manager](https://github.com/rmouahid/novit/blob/main/novit/scrapers/manager.py): `novit/scrapers/manager.py`
- **Source scrapers**
- [Polite HTTP client](https://github.com/rmouahid/novit/blob/main/novit/scrapers/http.py): `novit/scrapers/http.py`

### Article processing

- [Article model](https://github.com/rmouahid/novit/blob/main/novit/scrapers/base.py): `novit/scrapers/base.py`
- [Domain tagger](https://github.com/rmouahid/novit/blob/main/novit/scrapers/tagger.py): `novit/scrapers/tagger.py`
- [Deduplication](https://github.com/rmouahid/novit/blob/main/novit/scrapers/deduplication.py): `novit/scrapers/deduplication.py`
- [Article store](https://github.com/rmouahid/novit/blob/main/novit/scrapers/storage.py): `novit/scrapers/storage.py`
- [Offline fallback](https://github.com/rmouahid/novit/blob/main/novit/mcp/offline.py): `novit/mcp/offline.py`
- [Runtime settings](https://github.com/rmouahid/novit/blob/main/novit/settings.py): `novit/settings.py`

### User context

- [Profiles](https://github.com/rmouahid/novit/blob/main/novit/profiles/profile.py): `novit/profiles/profile.py`
- [Profile ranking](https://github.com/rmouahid/novit/blob/main/novit/profiles/filter.py): `novit/profiles/filter.py`
- [User preferences](https://github.com/rmouahid/novit/blob/main/novit/profiles/preferences.py): `novit/profiles/preferences.py`
- [User context](https://github.com/rmouahid/novit/blob/main/novit/mcp/users.py): `novit/mcp/users.py`
- [Sessions](https://github.com/rmouahid/novit/blob/main/novit/mcp/session.py): `novit/mcp/session.py`

### Insights and feedback

- [Daily summary](https://github.com/rmouahid/novit/blob/main/novit/mcp/daily.py): `novit/mcp/daily.py`
- [Trend analysis](https://github.com/rmouahid/novit/blob/main/novit/mcp/trends.py): `novit/mcp/trends.py`
- [Related articles](https://github.com/rmouahid/novit/blob/main/novit/mcp/related.py): `novit/mcp/related.py`
- [Unusual articles](https://github.com/rmouahid/novit/blob/main/novit/mcp/unusual.py): `novit/mcp/unusual.py`
- [User feedback](https://github.com/rmouahid/novit/blob/main/novit/mcp/feedback.py): `novit/mcp/feedback.py`
- [Health checks](https://github.com/rmouahid/novit/blob/main/novit/mcp/health.py): `novit/mcp/health.py`

### Other components

- **MCP client**
- **News sources**

## Connections

- MCP client → MCP server: calls tools
- MCP server → Tool handlers: dispatches tools (evidence: `novit/mcp/server.py`)
- MCP server → Tool schemas: declares contracts (evidence: `novit/mcp/server.py`)
- MCP server → HTTP transport: serves optionally (evidence: `novit/mcp/server.py`)
- Tool handlers → TTL cache: checks cache (evidence: `novit/mcp/handlers.py`)
- Tool handlers → Article store: reads and saves (evidence: `novit/mcp/handlers.py`)
- Tool handlers → Scraper manager: starts collection (evidence: `novit/mcp/handlers.py`)
- Tool handlers → Domain tagger: tags collected (evidence: `novit/mcp/handlers.py`)
- Tool handlers → Offline fallback: falls back (evidence: `novit/mcp/handlers.py`)
- Tool handlers → Profiles: selects profile (evidence: `novit/mcp/handlers.py`)
- Tool handlers → Profile ranking: ranks articles (evidence: `novit/mcp/handlers.py`)
- Scraper manager → Source scrapers: runs in parallel (evidence: `novit/scrapers/manager.py`)
- Scraper manager → Deduplication: deduplicates results (evidence: `novit/scrapers/manager.py`)
- Source scrapers → Polite HTTP client: fetches through (evidence: `novit/scrapers/http.py`)
- Polite HTTP client → News sources: requests articles
- Source scrapers → Article model: produces articles (evidence: `novit/scrapers/base.py`)
- Scraper manager → Article model: aggregates articles (evidence: `novit/scrapers/manager.py`)
- Domain tagger → Article model: annotates articles (evidence: `novit/scrapers/tagger.py`)
- Article store → Article model: stores articles (evidence: `novit/scrapers/storage.py`)
- Runtime settings → Polite HTTP client: configures requests (evidence: `novit/scrapers/http.py`)
- Runtime settings → Article store: configures database
- Profiles → Runtime settings: loads configuration (evidence: `novit/profiles/profile.py`)
- Profile ranking → Profiles: uses weights (evidence: `novit/profiles/filter.py`)
- Tool handlers → Daily summary: builds summaries (evidence: `novit/mcp/server.py`)
- Tool handlers → Trend analysis: dispatches analysis (evidence: `novit/mcp/server.py`)
- Tool handlers → Related articles: dispatches lookup
- Tool handlers → Unusual articles: dispatches lookup (evidence: `novit/mcp/server.py`)
- Tool handlers → User feedback: records feedback
- Tool handlers → Health checks: serves health (evidence: `novit/mcp/health.py`)
- User feedback → User context: captures context
- User preferences → User context: scopes preferences (evidence: `novit/profiles/preferences.py`)
- Sessions → User context: scopes sessions (evidence: `novit/mcp/session.py`)
- Trend analysis → Article store: reads articles (evidence: `novit/mcp/trends.py`)
- Related articles → Article store: reads articles (evidence: `novit/mcp/related.py`)
- Unusual articles → Article store: reads articles (evidence: `novit/mcp/unusual.py`)
