Architecture¶
Technical architecture and design decisions for MCP Notify.
System Overview¶
graph TB
subgraph External
R[MCP Registry]
U[Users]
N[Notification Channels]
end
subgraph MCP Notify
subgraph API Layer
HTTP[HTTP Server]
MW[Middleware]
end
subgraph Core Services
P[Poller]
D[Diff Engine]
S[Subscription Manager]
NO[Notifier Dispatcher]
end
subgraph Data Layer
PG[(PostgreSQL)]
RD[(Redis)]
end
subgraph MCP Interface
MCP[MCP Server]
end
end
R -->|Poll| P
P -->|Changes| D
D -->|Diffs| S
S -->|Match| NO
NO -->|Send| N
U -->|HTTP| HTTP
HTTP --> MW
MW --> S
S --> PG
P --> RD
MCP -->|Query| PG Components¶
Poller¶
The poller fetches the MCP Registry at configurable intervals.
Responsibilities:
- Fetch registry data on schedule
- Store snapshots for diffing
- Detect network failures and retry
Diff Engine¶
Compares registry snapshots to detect changes.
Go
type DiffEngine struct {
storage Storage
}
type Change struct {
Type ChangeType // New, Updated, Removed
ServerName string
OldData *Server
NewData *Server
Fields []FieldDiff
}
Change Detection:
| Change Type | Detection Method |
|---|---|
| New Server | Present in new, absent in old |
| Removed Server | Present in old, absent in new |
| Updated Server | Deep comparison of fields |
Subscription Manager¶
Manages user subscriptions and matches changes.
Go
type SubscriptionManager struct {
db *postgres.Client
matcher PatternMatcher
}
type Subscription struct {
ID string
UserID string
ServerPattern string // Glob pattern
NotifyOn []ChangeType
Channels []Channel
Active bool
}
Pattern Matching:
- Glob patterns:
claude-*,*-database,filesystem - Regex patterns:
^(claude|anthropic)-.*$ - Exact match:
filesystem
Notifier Dispatcher¶
Routes notifications to configured channels.
graph LR
D[Dispatcher] --> S[Slack Sender]
D --> DC[Discord Sender]
D --> E[Email Sender]
D --> T[Telegram Sender]
D --> MS[Teams Sender]
D --> W[Webhook Sender]
D --> R[RSS Generator] Each sender implements the Sender interface:
Go
type Sender interface {
Send(ctx context.Context, notification Notification) error
Type() string
}
API Server¶
RESTful HTTP API built with Go's standard library.
Middleware Stack:
| Middleware | Purpose |
|---|---|
| Logging | Request/response logging |
| Auth | API key validation |
| RateLimit | Request throttling |
MCP Server¶
Implements the Model Context Protocol for AI assistant integration.
Transport: stdio (standard input/output)
Tools Provided:
search_servers- Search by keywordget_server- Get server detailslist_servers- List all serversget_stats- Registry statistics
Data Flow¶
Subscription Creation¶
sequenceDiagram
participant U as User
participant A as API
participant V as Validator
participant D as Database
U->>A: POST /subscriptions
A->>V: Validate request
V-->>A: Valid
A->>D: Insert subscription
D-->>A: Created
A-->>U: 201 + subscription Change Detection & Notification¶
sequenceDiagram
participant P as Poller
participant R as Registry
participant D as Diff Engine
participant S as Sub Manager
participant N as Notifier
participant C as Channels
P->>R: Fetch registry
R-->>P: Server list
P->>D: Compare with previous
D-->>P: Changes detected
P->>S: Get matching subs
S-->>P: Subscriptions
P->>N: Dispatch notifications
N->>C: Send to channels Database Schema¶
Core Tables¶
erDiagram
users ||--o{ subscriptions : has
subscriptions ||--o{ channels : has
subscriptions ||--o{ notifications : receives
servers ||--o{ changes : has
users {
uuid id PK
string email
string api_key
timestamp created_at
}
subscriptions {
uuid id PK
uuid user_id FK
string server_pattern
array notify_on
boolean active
}
channels {
uuid id PK
uuid subscription_id FK
string type
jsonb config
}
servers {
uuid id PK
string name
string version
jsonb metadata
timestamp last_seen
}
changes {
uuid id PK
uuid server_id FK
string change_type
jsonb diff
timestamp detected_at
} Caching Strategy¶
Redis Usage¶
| Key Pattern | Data | TTL |
|---|---|---|
registry:snapshot | Latest registry | 5m |
registry:hash | Content hash | 5m |
server:{name} | Server details | 1h |
ratelimit:{ip} | Request count | 1m |
Cache Invalidation¶
- Snapshot cache invalidated on new poll
- Server cache invalidated on change detection
- Rate limit counters auto-expire
Scalability¶
Horizontal Scaling¶
graph TB
LB[Load Balancer]
subgraph App Servers
A1[Instance 1]
A2[Instance 2]
A3[Instance 3]
end
LB --> A1 & A2 & A3
A1 & A2 & A3 --> PG[(PostgreSQL Primary)]
A1 & A2 & A3 --> RD[(Redis Cluster)]
PG --> PGR[(PostgreSQL Replica)] Considerations¶
- Poller: Only one instance should poll (use leader election)
- API: Stateless, can scale horizontally
- Notifier: Queue-based for reliability
Security¶
Authentication¶
API keys are hashed with bcrypt and stored in PostgreSQL.
Rate Limiting¶
| Endpoint | Limit |
|---|---|
/api/* | 100/min |
/auth/* | 10/min |
/webhooks/* | 1000/min |
Data Protection¶
- Webhook URLs encrypted at rest
- API keys hashed
- TLS required in production