Compare commits

...

2 Commits

Author SHA1 Message Date
John Lancaster d1c80d4737 docs 2026-06-18 20:29:52 -05:00
John Lancaster c915c1846d docs 2026-06-18 20:01:47 -05:00
3 changed files with 273 additions and 360 deletions
+162
View File
@@ -0,0 +1,162 @@
---
icon: lucide/library
---
# Resource-First Pattern Module Architecture
## Overview
The platform is implemented as a resource-first MCP system with an integrated static documentation surface. The same methodology content powers both MCP resources and the published docs site.
The system is complete in three layers:
1. Canonical methodology is maintained in Markdown skill documents.
2. Catalog resources provide normalized discovery.
3. Zensical builds a static site from those same Markdown sources and the FastAPI app serves it in the FastMCP runtime process.
This architecture keeps authored content human-friendly while preserving machine-stable contracts.
## Intent
The architecture is designed to satisfy three long-term requirements:
1. Methodology must be editable as markdown by humans.
2. Agents must consume stable, discoverable resource contracts.
3. Public documentation must be pre-built static output served from the application runtime without a separate docs service.
## System Model
### Pattern Modules
Each module encapsulates one methodology domain and publishes resource families:
1. document
The document resource returns canonical Markdown, while clients can perform any downstream section extraction they need.
### Catalog Module
The catalog is the canonical discovery layer and publishes normalized records for all modules.
Typical catalog resources:
1. resource://catalog/patterns
2. resource://catalog/patterns_by_id
3. resource://catalog/skills_index
4. resource://catalog/skills_details
### Content Sources
Content is authored in markdown and managed as long-form reference material. Resource handlers expose the same authored documents through stable resource URIs.
### Static Docs Surface
Static docs are built directly from two markdown source streams:
1. Project-authored docs pages
2. Skill and reference markdown pages
The merged docs tree is built by Zensical into static files and served by the FastAPI app.
## Data Flow
```mermaid
flowchart TD
A[Authored Markdown] --> C[Resource Handlers]
B[Pattern Metadata] --> D[Catalog Resources]
A --> E[Zensical Static Build]
E --> H[FastAPI Static Mount]
H --> I[Served Docs Site]
D --> I
```
## Contracts
### Metadata Contract
Each pattern module declares:
1. id
2. name
3. version
4. description
5. tags
6. capabilities
7. depends_on
### URI Contract
Module resource URIs are stable and follow:
1. resource://skills/<skill_id>/document
Catalog resource URIs are stable and discovery-focused.
### Versioning Rule
Published URIs are immutable. Behavioral or schema changes are versioned in metadata and documented through additive migration notes.
## Static Hosting Pattern
The docs site is pre-built and served by the same FastAPI runtime process used by the MCP app.
Runtime behavior:
1. App starts.
2. FastAPI mounts the static docs output directory.
3. Requests to docs paths are served as static assets.
This provides a single deployment artifact with no runtime markdown rendering dependency.
## Advantages
### Single Source of Truth
Methodology is authored once and reused in both MCP resources and docs pages.
### High-Fidelity Agent Context
Resources expose the same canonical Markdown that humans author and review.
### Operational Simplicity
A single app process serves MCP and docs surfaces.
### Long-Term Maintainability
Markdown remains easy to review, while contracts remain stable for clients.
### Client Independence
Clients can use Ask, Edit, or Agent modes without requiring server-owned prompt orchestration.
## Authoring and Publishing Lifecycle
1. Update markdown reference content.
2. Update metadata if capability surface changes.
3. Build static docs with Zensical.
4. Serve built output through FastAPI static mount.
## Scope and Non-Goals
In-scope:
1. Resource-first methodology delivery
2. Catalog-based discovery
3. Pre-built static docs hosting in app runtime
Out-of-scope:
1. Prompt-first orchestration as the primary interface
2. Large tool inventories duplicating static guidance
3. Separate dynamic docs service at runtime
## Example Content Inputs
Existing markdown reference sets are valid examples of authored source material for this architecture:
1. ../skills/pytest-scaffolding/references/pytest-docs.md
2. ../skills/python-logging-dictconfig/references/python-logging-docs.md
3. ../skills/fastapi-uv-docker/references/fastapi-best-practices.md
These inputs are treated as content sources, while resource URIs and catalog payloads remain the machine-facing contracts.
+5
View File
@@ -3,3 +3,8 @@ icon: lucide/rocket
---
# Get started
## Architecture
- [Resource-First Pattern Module Architecture](./architecture.md)
- [Static Docs Hosting Pattern](./mcp_layout.md)
+106 -360
View File
@@ -1,408 +1,154 @@
For a modern Python project in 2026, I would treat the MCP server exactly like any other deployable service:
# Static Docs Hosting Pattern
* `src/` layout
* `uv` for dependency management
* skill modules as importable Python packages
* FastMCP composition via `mount()`
* Docker image built from the root package
* resources/prompts kept close to the skill that owns them
* avoid giant decorator files with hundreds of tools
## Purpose
FastMCP's mounting/composition model is specifically intended for this sort of modular organization. ([FastMCP][1])
This document describes the completed layout and runtime pattern used to host a pre-built static documentation site from the same FastAPI app process that runs the FastMCP server.
I'd structure it something like:
This design intentionally avoids runtime docs rendering and avoids a separate docs hosting service.
It also treats Markdown as the single source of truth for both MCP resources and published docs.
## Completed-State Layout
```text
personal-mcp/
├── pyproject.toml
├── uv.lock
├── README.md
├── Dockerfile
├── .dockerignore
├── src/
│ └── personal_mcp/
│ ├── __init__.py
│ │
│ ├── main.py
│ │ # Creates the root MCP server
│ │ # Mounts all skills
│ │
│ ├── settings.py
│ │ # Pydantic settings
│ │
│ ├── graph/
│ │ ├── __init__.py
│ │ └── capability_graph.py
│ │
│ ├── catalog/
│ │ ├── __init__.py
│ ├── resources.py
│ │ └── tools.py
│ │
│ └── skills/
├── __init__.py
│ │
├── nixos/
│ │
│ │ ├── __init__.py
│ │ ├── server.py
│ │ │
│ │ ├── tools/
│ │ │ └── rebuild.py
│ │ │
│ │ ├── prompts/
│ │ │ └── expert.py
│ │ │
│ │ ├── resources/
│ │ │ ├── overview.py
│ │ │ └── troubleshooting.py
│ │ │
│ │ └── metadata.yaml
│ │
│ ├── homelab/
│ │
│ │ ├── __init__.py
│ │ ├── server.py
│ │ ├── tools/
│ │ ├── prompts/
│ │ ├── resources/
│ │ └── metadata.yaml
│ │
│ └── knowledge_base/
│ ├── __init__.py
│ ├── server.py
│ ├── tools/
│ ├── prompts/
│ ├── resources/
│ └── metadata.yaml
└── tests/
├── test_catalog.py
├── test_nixos.py
└── test_homelab.py
project-root/
|
|- pyproject.toml
|- uv.lock
|- zensical.toml
|
|- docs/
| |- index.md
| |- architecture.md
| |- mcp_layout.md
|
|- site/
| |- ... static files built by zensical ...
|
|- skills/
| |- pytest-scaffolding/
| | |- SKILL.md
| | |- references/
| |- python-logging-dictconfig/
| | |- SKILL.md
| | |- references/
| |- fastapi-uv-docker/
| |- SKILL.md
| |- references/
|
|- src/
|- personal_mcp/
|- main.py
|- web/
| |- app.py
| |- docs_mount.py
|- catalog/
| |- server.py
|- skills/
|- pytest_scaffolding/
|- python_logging_dictconfig/
|- fastapi_uv_docker/
```
---
Notes:
## main.py
1. docs contains project-authored pages.
2. site contains static build output only.
3. skills contains canonical skill Markdown and reference Markdown.
4. MCP resources and docs site read from the same Markdown sources.
This is intentionally boring.
## Runtime Composition
```python
from fastmcp import FastMCP
The runtime process serves two surfaces:
from personal_mcp.catalog.server import catalog_server
from personal_mcp.skills.nixos.server import nixos_server
from personal_mcp.skills.homelab.server import homelab_server
1. MCP protocol surface from FastMCP
2. Static docs surface from FastAPI static mount
mcp = FastMCP("Personal MCP")
mcp.mount(catalog_server, namespace="catalog")
mcp.mount(nixos_server, namespace="nixos")
mcp.mount(homelab_server, namespace="homelab")
if __name__ == "__main__":
mcp.run()
```mermaid
flowchart TD
A[FastMCP Root Server] --> B[MCP Transport]
A --> C[FastAPI Application]
C --> D[Static Mount /docs]
D --> E[Zensical site output directory]
```
FastMCP namespaces resources, prompts, and tools automatically when mounted. ([FastMCP][2])
## Build and Publish Flow
---
The docs flow is pre-build only.
## Skill Metadata
1. Read authored docs pages and skill markdown sources.
2. Build static site with Zensical into site.
3. Start app and serve site directory as static files.
Every skill gets metadata.
No runtime markdown conversion is required.
```yaml
# skills/nixos/metadata.yaml
## Content Merge Pattern
id: nixos
The published docs site always contains both:
name: NixOS Administration
1. Project-authored docs pages
2. Skill Markdown content from skills/*/SKILL.md and references
description: |
Tools and guidance for managing NixOS systems.
This ensures the public docs reflect architectural guidance and the exact Markdown served by MCP.
tags:
- nix
- linux
- systemd
## Markdown-to-Resource Mapping
capabilities:
- package_management
- service_debugging
- flakes
MCP resources map directly to canonical Markdown documents.
depends_on:
- certificates
```
Example mapping model:
The catalog layer reads these files.
1. skills/<slug>/SKILL.md -> resource://skills/<id>/document
2. skills/<slug>/references/*.md -> referenced sections or linked companion documents
---
Catalog resources provide discovery metadata and stable identifiers.
## Skill Server
## Why This Pattern
Each skill owns its own MCP instance.
### Operational Simplicity
```python
# skills/nixos/server.py
One application process serves both protocol and static docs surfaces.
from fastmcp import FastMCP
### Deterministic Docs
nixos_server = FastMCP(
"NixOS"
)
Published docs are immutable static assets for a given build.
from .tools.rebuild import *
from .resources.overview import *
from .prompts.expert import *
```
### Documentation Fidelity
The pattern is:
The docs site and MCP resources resolve from the same Markdown sources.
```text
One skill
=
One FastMCP server
```
### Maintainer Experience
This keeps ownership obvious.
Authors continue to work in markdown while resource contracts remain machine-consumable.
---
## FastAPI Static Mount Expectations
## Skill Resource
The FastAPI app is expected to:
Resources are your discovery layer.
1. Mount static directory containing Zensical output.
2. Serve index and asset files from that directory.
3. Keep docs route stable across releases.
```python
# resources/overview.py
Recommended route conventions:
from .server import nixos_server
1. /docs for static site root
2. /docs/* for static assets and page routes
## Update Lifecycle
@nixos_server.resource(
"resource://skills/nixos"
)
def nixos_skill_description():
return """
NixOS administration skill.
For each documentation update:
Provides:
- flake troubleshooting
- package search
- service diagnostics
- generation management
"""
```
1. Edit authored docs and skill markdown content.
2. Rebuild static site.
3. Restart runtime if needed.
Resources are exactly what MCP intends for exposing contextual information and data to clients. ([fastmcp.mintlify.app][3])
This keeps docs publication explicit and predictable.
---
## Example Source Material
## Skill Prompt
Existing reference docs remain valid content inputs in this pattern:
```python
# prompts/expert.py
1. ../skills/pytest-scaffolding/references/pytest-docs.md
2. ../skills/python-logging-dictconfig/references/python-logging-docs.md
3. ../skills/fastapi-uv-docker/references/fastapi-best-practices.md
from .server import nixos_server
@nixos_server.prompt
def nixos_expert():
return """
Act as an expert NixOS administrator.
Prefer:
- flakes
- declarative configuration
- modern systemd patterns
Avoid:
- imperative package management
"""
```
---
## Skill Tool
```python
# tools/rebuild.py
from .server import nixos_server
@nixos_server.tool
def explain_rebuild():
"""
Explain a nixos-rebuild failure.
"""
return {
"workflow": [
"Inspect journal",
"Check evaluation errors",
"Verify inputs",
"Retry build"
]
}
```
---
## Catalog Layer
The catalog should be its own server.
Not a skill.
Its job is discovery.
```python
catalog/
server.py
tools.py
resources.py
```
Example:
```python
# catalog/tools.py
@catalog_server.tool
def list_skills():
return [
"nixos",
"homelab",
"knowledge_base"
]
```
```python
@catalog_server.tool
def describe_skill(
name: str
):
...
```
---
## Capability Graph
This is where NetworkX belongs.
```python
# graph/capability_graph.py
import networkx as nx
graph = nx.DiGraph()
graph.add_edge(
"homelab",
"certificates",
relation="depends_on"
)
graph.add_edge(
"nixos",
"homelab",
relation="manages"
)
```
Expose it as:
```python
resource://skills/graph
resource://skills/nixos/dependencies
```
Now agents can discover related capabilities without hardcoding them.
---
## pyproject.toml
Minimal UV setup:
```toml
[project]
name = "personal-mcp"
version = "0.1.0"
dependencies = [
"fastmcp",
"networkx",
"pydantic-settings",
"pyyaml",
]
[project.scripts]
personal-mcp = "personal_mcp.main:mcp"
```
---
## Docker
```dockerfile
FROM python:3.13-slim
WORKDIR /app
COPY pyproject.toml uv.lock ./
RUN pip install uv
RUN uv sync --frozen
COPY src ./src
CMD ["uv", "run", "python", "-m", "personal_mcp.main"]
```
---
If I were building this for long-term growth, I'd make one additional change: treat every skill as a Python package with a common interface:
```python
class Skill:
id: str
metadata: SkillMetadata
def create_server(self) -> FastMCP:
...
```
Then `main.py` simply discovers skills dynamically:
```python
for skill in discover_skills():
mcp.mount(
skill.create_server(),
namespace=skill.id,
)
```
At that point adding a new skill becomes:
```text
mkdir skills/new_skill
drop in metadata.yaml
implement Skill
```
and the server automatically exposes it. That's the closest thing to a plugin architecture while still remaining very Pythonic and Docker-friendly.
[1]: https://fastmcp.wiki/en/servers/composition?utm_source=chatgpt.com "Server Composition - FastMCP"
[2]: https://gofastmcp.com/servers/composition?utm_source=chatgpt.com "Composing Servers - FastMCP"
[3]: https://fastmcp.mintlify.app/servers/resources?utm_source=chatgpt.com "Resources & Templates - FastMCP"
These are source documents, not deployment artifacts.