feat(mcpedia): Phase 1 MVP — monorepo, Core, Web UI, MCP server, Postgres FTS
- bun workspaces + Turborepo monorepo (apps/web, apps/mcp; packages/*, scripts) - @mcpedia/core single business-logic layer (Document/Content/Search services) - @mcpedia/db Drizzle schema: documents + weighted tsvector (GIN) for FTS - @mcpedia/parser frontmatter, @mcpedia/search Postgres FTS (ts_rank+ts_headline) - Next.js 16 Web UI (home/doc SSG, search dynamic) + react-markdown render - MCP server (stdio) with 4 tools + in-memory smoke test - scripts/indexer walks content/ -> upserts into Postgres - 4 seed docs; README + PHASES status
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
---
|
||||
id: websocket-contract
|
||||
title: WebSocket Contract
|
||||
type: documentation
|
||||
tags:
|
||||
- typescript
|
||||
- websocket
|
||||
- rpc
|
||||
status: published
|
||||
author: asep
|
||||
created_at: 2026-08-19
|
||||
updated_at: 2026-08-19
|
||||
---
|
||||
|
||||
# WebSocket Contract
|
||||
|
||||
The WebSocket contract defines how clients establish a bidirectional connection
|
||||
and exchange RPC-style messages with the server. It is the foundation for the
|
||||
type-safe API described in the tRPC integration notes.
|
||||
|
||||
## Handshake
|
||||
|
||||
A client opens a single WebSocket connection and sends an `init` frame携带 an
|
||||
auth token. The server answers with `ready` or closes the socket with code 4401
|
||||
if the token is invalid.
|
||||
|
||||
## Message envelope
|
||||
|
||||
Every frame uses a JSON envelope:
|
||||
|
||||
```json
|
||||
{ "id": "req-1", "method": "echo", "params": { "text": "hi" } }
|
||||
```
|
||||
|
||||
The server replies with a matching `id` and either a `result` or an `error`
|
||||
field. This request/response correlation is what makes the protocol feel like
|
||||
RPC even though it rides on a single socket.
|
||||
|
||||
## Timeouts
|
||||
|
||||
If the server does not answer within the negotiated timeout, the client should
|
||||
re-send with the same `id` rather than opening a new connection. See the
|
||||
debugging writeup for a common timeout pitfall when proxies buffer frames.
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
id: typescript-patterns
|
||||
title: TypeScript Patterns
|
||||
type: note
|
||||
tags:
|
||||
- typescript
|
||||
- patterns
|
||||
status: published
|
||||
author: asep
|
||||
created_at: 2026-08-19
|
||||
updated_at: 2026-08-19
|
||||
---
|
||||
|
||||
# TypeScript Patterns
|
||||
|
||||
A notebook of small, reusable TypeScript patterns that keep code honest.
|
||||
|
||||
## Branded types for ids
|
||||
|
||||
```ts
|
||||
type DocId = string & { readonly __brand: "DocId" };
|
||||
const asDocId = (s: string) => s as DocId;
|
||||
```
|
||||
|
||||
Branding prevents passing an arbitrary string where a document id is expected.
|
||||
|
||||
## Discriminated unions over inheritance
|
||||
|
||||
Prefer a closed set of variants with a `kind` field. Exhaustiveness checks with
|
||||
`switch` catch missing cases at compile time instead of at runtime.
|
||||
|
||||
## Prefer composition
|
||||
|
||||
When two modules share behavior, extract a function. Avoid inheritance trees
|
||||
that couple unrelated code. This matches the MCPedia Core principle: one layer
|
||||
owns the logic, interfaces only call into it.
|
||||
@@ -0,0 +1,34 @@
|
||||
---
|
||||
id: mcp-architecture
|
||||
title: MCP Architecture Notes
|
||||
type: research
|
||||
tags:
|
||||
- mcp
|
||||
- architecture
|
||||
- ai
|
||||
status: published
|
||||
author: asep
|
||||
created_at: 2026-08-19
|
||||
updated_at: 2026-08-19
|
||||
---
|
||||
|
||||
# MCP Architecture Notes
|
||||
|
||||
The Model Context Protocol (MCP) lets an AI client treat a knowledge base as a
|
||||
first-class context source instead of yet another REST API. The server exposes
|
||||
tools and resources; the client decides what to read.
|
||||
|
||||
## Tools vs resources
|
||||
|
||||
- Tools are actions the model calls (`search_documents`, `get_document`).
|
||||
- Resources are addressable content the model can pull (`mcpedia://docs/...`).
|
||||
|
||||
## Why it matters here
|
||||
|
||||
MCPedia exposes both. The Web UI is for humans; the MCP server is for agents.
|
||||
Both go through the same Core layer, so there is exactly one copy of the
|
||||
business logic and one search implementation.
|
||||
|
||||
## Reference
|
||||
|
||||
Related reading: the WebSocket contract and the tRPC type-safe API notes.
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
id: websocket-timeout
|
||||
title: Debugging a WebSocket Timeout Behind a Proxy
|
||||
type: writeup
|
||||
tags:
|
||||
- websocket
|
||||
- debugging
|
||||
- proxy
|
||||
status: published
|
||||
author: asep
|
||||
created_at: 2026-08-19
|
||||
updated_at: 2026-08-19
|
||||
---
|
||||
|
||||
# Debugging a WebSocket Timeout Behind a Proxy
|
||||
|
||||
A recurring incident: the browser WebSocket connects, sends one frame, then
|
||||
silently times out. The server logs show no error. Root cause: the reverse
|
||||
proxy was buffering frames and only flushing on connection close.
|
||||
|
||||
## Symptoms
|
||||
|
||||
- Connection opens (101 Switching Protocols).
|
||||
- First message never reaches the upstream.
|
||||
- Client hits its own 30s timeout and reconnects, creating a storm.
|
||||
|
||||
## Fix
|
||||
|
||||
Disable proxy buffering for the WebSocket upgrade route and ensure the proxy
|
||||
does not apply an idle timeout shorter than the application's heartbeat
|
||||
interval. After that, frames flowed immediately and the timeout disappeared.
|
||||
|
||||
## Lesson
|
||||
|
||||
Always confirm at the proxy layer whether frames are buffered before assuming
|
||||
the application server is at fault.
|
||||
Reference in New Issue
Block a user