From f970e1219d27eb46a8e5b67e91b0a9b4bd9f0cd6 Mon Sep 17 00:00:00 2001 From: Riz Ashraf Date: Sun, 27 Sep 2026 21:49:41 +0100 Subject: [PATCH] docs: Add architecture design for MCP resources and prompts trait refactor --- ARCHITECTURE_RESOURCES_PROMPTS.md | 77 +++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 ARCHITECTURE_RESOURCES_PROMPTS.md diff --git a/ARCHITECTURE_RESOURCES_PROMPTS.md b/ARCHITECTURE_RESOURCES_PROMPTS.md new file mode 100644 index 0000000..b0d905c --- /dev/null +++ b/ARCHITECTURE_RESOURCES_PROMPTS.md @@ -0,0 +1,77 @@ +# Architecture Design: MCP Resources & Prompts + +## 1. Current Architecture (Tools) +Currently, the `mcp-memory` server handles MCP tools using an elegant trait-based approach in `router.rs`: +```rust +#[async_trait] +pub trait McpTool: Send + Sync { + fn name(&self) -> &'static str; + fn schema(&self) -> Value; + async fn execute(&self, args: Value, state: Arc) -> Result; +} +``` +Tools are registered into a `HashMap>` within the `MemoryHandler`. This prevents the main JSON-RPC match block from becoming a monolithic switch statement. + +## 2. The Problem +Currently, the `resources/list`, `resources/read`, `prompts/list`, and `prompts/get` endpoints are hardcoded directly inside the `MemoryHandler::handle_request` match block in `router.rs`. +As we expand our usage of Resources (to expose the database state dynamically) and Prompts (to bundle complex workflows), continuing to hardcode them in `router.rs` will result in massive code duplication and tearup. + +## 3. The Proposed Solution (Trait Extensibility) +We will replicate the success of the `McpTool` trait by introducing `McpResource` and `McpPrompt` traits. + +### A. MCP Resources +**Trait Definition (`router.rs` or `resources.rs`):** +```rust +#[async_trait] +pub trait McpResource: Send + Sync { + /// The exact URI the client requests (e.g. "memory://tasks/active") + fn uri(&self) -> &'static str; + + /// Human-readable name for the client UI + fn name(&self) -> &'static str; + + /// Description for the client UI + fn description(&self) -> Option<&'static str> { None } + + /// Mime type of the content (usually "application/json" or "text/markdown") + fn mime_type(&self) -> Option<&'static str> { Some("application/json") } + + /// Retrieve the resource content + async fn read(&self, state: Arc) -> Result; +} +``` +**Implementation:** +* Add `pub resources: std::collections::HashMap>` to `MemoryHandler`. +* In `handle_request("resources/list")`, iterate over `self.resources.values()` and build the JSON payload. +* In `handle_request("resources/read")`, lookup the requested URI in `self.resources` and call `.read(state).await`. +* Move the existing `memory://graph/entities` logic into its own handler struct. + +### B. MCP Prompts +**Trait Definition (`router.rs` or `prompts.rs`):** +```rust +#[async_trait] +pub trait McpPrompt: Send + Sync { + /// The unique name of the prompt (e.g. "analyze_tech_debt") + fn name(&self) -> &'static str; + + /// Description for the client UI + fn description(&self) -> Option<&'static str> { None } + + /// Schema or array defining arguments (can default to empty) + fn arguments(&self) -> serde_json::Value { serde_json::json!([]) } + + /// Execute the prompt and return the `messages` array payload + async fn get(&self, args: Value, state: Arc) -> Result; +} +``` +**Implementation:** +* Add `pub prompts: std::collections::HashMap>` to `MemoryHandler`. +* In `handle_request("prompts/list")`, map over `self.prompts.values()`. +* In `handle_request("prompts/get")`, call `.get(args, state).await`. + +## 4. Execution Plan +1. **Refactor `router.rs` (No functional changes yet):** Define the `McpResource` and `McpPrompt` traits. Update the `MemoryHandler` struct to hold these HashMaps. Migrate the existing hardcoded stubs (`memory://graph/entities` and `analyze_tech_debt`) into structs implementing these traits. +2. **Expand Resources (Phase 1):** Add new handlers for `memory://tasks/active`, `memory://pinned_files`, etc. +3. **Expand Prompts (Phase 2):** Add new handlers for `handoff_routine`, etc. + +This design guarantees we do not needlessly tear up code—we merely extend the existing robust `McpTool` pattern to the rest of the protocol.