docs: ProxyModel authoring guide in README, mark cache tasks done
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2078,9 +2078,9 @@
|
||||
"dependencies": [
|
||||
"82"
|
||||
],
|
||||
"status": "deferred",
|
||||
"status": "cancelled",
|
||||
"subtasks": [],
|
||||
"updatedAt": "2026-02-28T01:07:00.043Z"
|
||||
"updatedAt": "2026-03-07T01:27:15.554Z"
|
||||
},
|
||||
{
|
||||
"id": "84",
|
||||
@@ -2106,9 +2106,9 @@
|
||||
"dependencies": [
|
||||
"79"
|
||||
],
|
||||
"status": "deferred",
|
||||
"status": "done",
|
||||
"subtasks": [],
|
||||
"updatedAt": "2026-02-28T01:07:00.050Z"
|
||||
"updatedAt": "2026-03-07T02:38:57.221Z"
|
||||
},
|
||||
{
|
||||
"id": "86",
|
||||
@@ -2120,9 +2120,9 @@
|
||||
"dependencies": [
|
||||
"78"
|
||||
],
|
||||
"status": "deferred",
|
||||
"status": "done",
|
||||
"subtasks": [],
|
||||
"updatedAt": "2026-02-28T01:07:00.059Z"
|
||||
"updatedAt": "2026-03-07T02:38:57.226Z"
|
||||
},
|
||||
{
|
||||
"id": "87",
|
||||
@@ -2132,7 +2132,7 @@
|
||||
"testStrategy": "Database migration test: verify migration applies cleanly. API tests: verify proxyModel field is returned in project GET, can be updated via PATCH. CLI tests: verify `mcpctl describe project <name>` shows proxyModel.",
|
||||
"priority": "high",
|
||||
"dependencies": [],
|
||||
"status": "deferred",
|
||||
"status": "cancelled",
|
||||
"subtasks": [
|
||||
{
|
||||
"id": 1,
|
||||
@@ -2145,7 +2145,7 @@
|
||||
"parentId": "undefined"
|
||||
}
|
||||
],
|
||||
"updatedAt": "2026-02-28T01:07:00.065Z"
|
||||
"updatedAt": "2026-03-07T01:27:15.571Z"
|
||||
},
|
||||
{
|
||||
"id": "88",
|
||||
@@ -2157,9 +2157,9 @@
|
||||
"dependencies": [
|
||||
"87"
|
||||
],
|
||||
"status": "deferred",
|
||||
"status": "cancelled",
|
||||
"subtasks": [],
|
||||
"updatedAt": "2026-02-28T01:07:00.071Z"
|
||||
"updatedAt": "2026-03-07T23:36:15.209Z"
|
||||
},
|
||||
{
|
||||
"id": "89",
|
||||
@@ -2172,9 +2172,9 @@
|
||||
"78",
|
||||
"79"
|
||||
],
|
||||
"status": "deferred",
|
||||
"status": "cancelled",
|
||||
"subtasks": [],
|
||||
"updatedAt": "2026-02-28T01:07:00.076Z"
|
||||
"updatedAt": "2026-03-07T01:27:15.577Z"
|
||||
},
|
||||
{
|
||||
"id": "90",
|
||||
@@ -2186,9 +2186,9 @@
|
||||
"dependencies": [
|
||||
"79"
|
||||
],
|
||||
"status": "deferred",
|
||||
"status": "cancelled",
|
||||
"subtasks": [],
|
||||
"updatedAt": "2026-02-28T01:07:00.082Z"
|
||||
"updatedAt": "2026-03-07T01:27:15.582Z"
|
||||
},
|
||||
{
|
||||
"id": "91",
|
||||
@@ -2200,9 +2200,9 @@
|
||||
"dependencies": [
|
||||
"78"
|
||||
],
|
||||
"status": "deferred",
|
||||
"status": "cancelled",
|
||||
"subtasks": [],
|
||||
"updatedAt": "2026-02-28T01:07:00.087Z"
|
||||
"updatedAt": "2026-03-07T01:27:15.587Z"
|
||||
},
|
||||
{
|
||||
"id": "92",
|
||||
@@ -2214,9 +2214,9 @@
|
||||
"dependencies": [
|
||||
"79"
|
||||
],
|
||||
"status": "deferred",
|
||||
"status": "cancelled",
|
||||
"subtasks": [],
|
||||
"updatedAt": "2026-02-28T01:07:00.092Z"
|
||||
"updatedAt": "2026-03-07T01:27:15.592Z"
|
||||
},
|
||||
{
|
||||
"id": "93",
|
||||
@@ -2228,9 +2228,9 @@
|
||||
"dependencies": [
|
||||
"71"
|
||||
],
|
||||
"status": "deferred",
|
||||
"status": "cancelled",
|
||||
"subtasks": [],
|
||||
"updatedAt": "2026-02-28T01:07:00.098Z"
|
||||
"updatedAt": "2026-03-07T01:27:15.598Z"
|
||||
},
|
||||
{
|
||||
"id": "94",
|
||||
@@ -2242,9 +2242,9 @@
|
||||
"dependencies": [
|
||||
"78"
|
||||
],
|
||||
"status": "deferred",
|
||||
"status": "cancelled",
|
||||
"subtasks": [],
|
||||
"updatedAt": "2026-02-28T01:07:00.102Z"
|
||||
"updatedAt": "2026-03-07T01:27:15.605Z"
|
||||
},
|
||||
{
|
||||
"id": "95",
|
||||
@@ -2257,9 +2257,9 @@
|
||||
"78",
|
||||
"79"
|
||||
],
|
||||
"status": "deferred",
|
||||
"status": "cancelled",
|
||||
"subtasks": [],
|
||||
"updatedAt": "2026-02-28T01:07:00.107Z"
|
||||
"updatedAt": "2026-03-07T01:27:15.613Z"
|
||||
},
|
||||
{
|
||||
"id": "96",
|
||||
@@ -2271,9 +2271,9 @@
|
||||
"dependencies": [
|
||||
"79"
|
||||
],
|
||||
"status": "deferred",
|
||||
"status": "cancelled",
|
||||
"subtasks": [],
|
||||
"updatedAt": "2026-02-28T01:07:00.116Z"
|
||||
"updatedAt": "2026-03-07T01:27:15.619Z"
|
||||
},
|
||||
{
|
||||
"id": "97",
|
||||
@@ -2285,9 +2285,9 @@
|
||||
"dependencies": [
|
||||
"78"
|
||||
],
|
||||
"status": "deferred",
|
||||
"status": "cancelled",
|
||||
"subtasks": [],
|
||||
"updatedAt": "2026-02-28T01:07:00.122Z"
|
||||
"updatedAt": "2026-03-07T01:27:15.625Z"
|
||||
},
|
||||
{
|
||||
"id": "98",
|
||||
@@ -2299,9 +2299,9 @@
|
||||
"dependencies": [
|
||||
"73"
|
||||
],
|
||||
"status": "deferred",
|
||||
"status": "done",
|
||||
"subtasks": [],
|
||||
"updatedAt": "2026-02-28T01:07:00.128Z"
|
||||
"updatedAt": "2026-03-07T23:36:15.877Z"
|
||||
},
|
||||
{
|
||||
"id": "99",
|
||||
@@ -2313,9 +2313,9 @@
|
||||
"dependencies": [
|
||||
"98"
|
||||
],
|
||||
"status": "deferred",
|
||||
"status": "done",
|
||||
"subtasks": [],
|
||||
"updatedAt": "2026-02-28T01:07:00.134Z"
|
||||
"updatedAt": "2026-03-07T23:36:15.892Z"
|
||||
},
|
||||
{
|
||||
"id": "100",
|
||||
@@ -2327,9 +2327,9 @@
|
||||
"dependencies": [
|
||||
"98"
|
||||
],
|
||||
"status": "deferred",
|
||||
"status": "done",
|
||||
"subtasks": [],
|
||||
"updatedAt": "2026-02-28T01:11:23.496Z"
|
||||
"updatedAt": "2026-03-07T23:36:15.902Z"
|
||||
},
|
||||
{
|
||||
"id": "101",
|
||||
@@ -2341,9 +2341,9 @@
|
||||
"dependencies": [
|
||||
"98"
|
||||
],
|
||||
"status": "deferred",
|
||||
"status": "done",
|
||||
"subtasks": [],
|
||||
"updatedAt": "2026-02-28T01:11:23.501Z"
|
||||
"updatedAt": "2026-03-07T23:36:15.957Z"
|
||||
},
|
||||
{
|
||||
"id": "102",
|
||||
@@ -2355,9 +2355,9 @@
|
||||
"dependencies": [
|
||||
"98"
|
||||
],
|
||||
"status": "deferred",
|
||||
"status": "done",
|
||||
"subtasks": [],
|
||||
"updatedAt": "2026-02-28T01:11:23.507Z"
|
||||
"updatedAt": "2026-03-07T23:36:15.981Z"
|
||||
},
|
||||
{
|
||||
"id": "103",
|
||||
@@ -2380,9 +2380,9 @@
|
||||
"101",
|
||||
"102"
|
||||
],
|
||||
"status": "deferred",
|
||||
"status": "cancelled",
|
||||
"subtasks": [],
|
||||
"updatedAt": "2026-02-28T01:07:00.141Z"
|
||||
"updatedAt": "2026-03-07T01:27:15.630Z"
|
||||
},
|
||||
{
|
||||
"id": "104",
|
||||
@@ -2394,9 +2394,9 @@
|
||||
"dependencies": [
|
||||
"80"
|
||||
],
|
||||
"status": "deferred",
|
||||
"status": "cancelled",
|
||||
"subtasks": [],
|
||||
"updatedAt": "2026-02-28T01:07:00.147Z"
|
||||
"updatedAt": "2026-03-07T01:27:15.636Z"
|
||||
},
|
||||
{
|
||||
"id": "105",
|
||||
@@ -2408,9 +2408,9 @@
|
||||
"dependencies": [
|
||||
"104"
|
||||
],
|
||||
"status": "deferred",
|
||||
"status": "done",
|
||||
"subtasks": [],
|
||||
"updatedAt": "2026-02-28T01:11:23.514Z"
|
||||
"updatedAt": "2026-03-07T02:22:03.301Z"
|
||||
},
|
||||
{
|
||||
"id": "106",
|
||||
@@ -2422,9 +2422,9 @@
|
||||
"dependencies": [
|
||||
"105"
|
||||
],
|
||||
"status": "deferred",
|
||||
"status": "done",
|
||||
"subtasks": [],
|
||||
"updatedAt": "2026-02-28T01:11:23.521Z"
|
||||
"updatedAt": "2026-03-07T02:32:05.366Z"
|
||||
},
|
||||
{
|
||||
"id": "107",
|
||||
@@ -2436,9 +2436,9 @@
|
||||
"dependencies": [
|
||||
"106"
|
||||
],
|
||||
"status": "deferred",
|
||||
"status": "done",
|
||||
"subtasks": [],
|
||||
"updatedAt": "2026-02-28T01:11:23.528Z"
|
||||
"updatedAt": "2026-03-07T02:32:05.373Z"
|
||||
},
|
||||
{
|
||||
"id": "108",
|
||||
@@ -2451,9 +2451,9 @@
|
||||
"105",
|
||||
"82"
|
||||
],
|
||||
"status": "deferred",
|
||||
"status": "done",
|
||||
"subtasks": [],
|
||||
"updatedAt": "2026-02-28T01:11:23.534Z"
|
||||
"updatedAt": "2026-03-07T02:22:03.308Z"
|
||||
},
|
||||
{
|
||||
"id": "109",
|
||||
@@ -2468,9 +2468,9 @@
|
||||
"107",
|
||||
"108"
|
||||
],
|
||||
"status": "deferred",
|
||||
"status": "done",
|
||||
"subtasks": [],
|
||||
"updatedAt": "2026-02-28T01:11:23.542Z"
|
||||
"updatedAt": "2026-03-07T02:32:05.393Z"
|
||||
},
|
||||
{
|
||||
"id": "110",
|
||||
@@ -2499,9 +2499,9 @@
|
||||
"82",
|
||||
"83"
|
||||
],
|
||||
"status": "deferred",
|
||||
"status": "done",
|
||||
"subtasks": [],
|
||||
"updatedAt": "2026-02-28T01:07:00.158Z"
|
||||
"updatedAt": "2026-03-07T03:02:47.422Z"
|
||||
},
|
||||
{
|
||||
"id": "112",
|
||||
@@ -2516,9 +2516,9 @@
|
||||
"93",
|
||||
"94"
|
||||
],
|
||||
"status": "deferred",
|
||||
"status": "done",
|
||||
"subtasks": [],
|
||||
"updatedAt": "2026-02-28T01:07:00.164Z"
|
||||
"updatedAt": "2026-03-07T03:02:47.439Z"
|
||||
},
|
||||
{
|
||||
"id": "113",
|
||||
@@ -2534,28 +2534,28 @@
|
||||
"108",
|
||||
"109"
|
||||
],
|
||||
"status": "deferred",
|
||||
"status": "done",
|
||||
"subtasks": [],
|
||||
"updatedAt": "2026-02-28T01:11:23.552Z"
|
||||
"updatedAt": "2026-03-07T02:22:17.268Z"
|
||||
},
|
||||
{
|
||||
"id": "114",
|
||||
"title": "ProxyModel v2: Code-based MCP middleware plugin system",
|
||||
"description": "Redesign the ProxyModel framework from a YAML-configured content transformation pipeline into a full code-based MCP middleware plugin system. Proxy models become TypeScript files that can intercept any MCP request/response, create synthetic tools, maintain per-session state, and compose via multiple inheritance with compile-time conflict detection. The existing gate functionality (begin_session, tools/list filtering, prompt scoring, ungating) becomes the first proxy model implementation, proving the framework works by implementing gate entirely as a plugin with zero gate-specific code in router.ts.",
|
||||
"details": "## Vision\n\nA proxy model is a TypeScript code file (not YAML) that acts as full MCP middleware. It can:\n- Intercept any MCP request (initialize, tools/list, tools/call, resources/*, prompts/*)\n- Modify any response before it reaches the client\n- Create synthetic tools (e.g. begin_session doesn't exist upstream)\n- Maintain per-session state (gated/ungated, accumulated tags, etc.)\n- Access project resources (prompts, servers, config)\n- Transform content (what stages do today: paginate, section-split, etc.)\n\n## Key design decisions\n\n1. Code not YAML: Proxy models live as .ts files in a known directory (e.g. ~/.mcpctl/proxymodels/). File exists = model exists. No create/delete via CLI.\n2. Stages deprecated: No separate stage resource. Content transformation is just code inside the proxy model.\n3. Multiple inheritance: A model can extend [gate, subindex] to compose behaviors from multiple parents. Conflicts (two parents intercepting the same method incompatibly) detected at load/compile time, not runtime.\n4. Gate is just a proxy model: The ~300 lines of gate logic in router.ts move into a gate.ts proxy model file. Router becomes thin plumbing (~100 lines).\n5. gated:true replaced by proxyModel field: Projects get a proxyModel: gate field. If the assigned model implements gating, the project is gated. No separate boolean.\n6. Discoverable as resources: mcpctl get proxymodels lists available models (discovered from files). mcpctl describe proxymodel gate shows details. But no create/delete commands.\n7. Attached to projects: mcpctl edit project foo --proxyModel gate or via apply YAML.\n\n## Framework interface (sketch)\n\nexport interface ProxyModelContext {\n session: SessionState;\n project: ProjectConfig;\n upstream: UpstreamClient;\n llm?: LLMProvider;\n cache?: CacheProvider;\n}\n\nexport interface ProxyModel {\n name: string;\n extends?: string[];\n onInitialize?(ctx, request): Promise<InitializeResult>;\n onToolsList?(ctx): Promise<Tool[]>;\n onToolCall?(ctx, name, args): Promise<ToolResult | null>;\n onResourceRead?(ctx, uri): Promise<ResourceContent | null>;\n transformContent?(ctx, content, contentType): Promise<string>;\n createSessionState?(): Record<string, unknown>;\n}\n\n## Migration path\n\n1. Define the ProxyModel TypeScript interface\n2. Implement the plugin loader (discover .ts files, compile, validate inheritance, detect conflicts)\n3. Implement the router integration (router delegates to loaded proxy model)\n4. Extract gate logic from router.ts into gate.ts proxy model\n5. Extract content pipeline (passthrough, paginate, section-split) into proxy model code\n6. Add proxyModel field to Project schema (replaces gated boolean)\n7. Add CLI: get proxymodels, describe proxymodel, edit project --proxyModel\n8. Add smoke tests: gate proxy model produces identical behavior to current hardcoded gate\n9. Deprecate gated field (backward compat: gated:true maps to proxyModel:gate)\n\n## Supersedes\n\nThis task supersedes deferred tasks 83, 85-97, 98-99, 103, 104, 110, 111-112 which assumed the old YAML/stage architecture.",
|
||||
"status": "in-progress",
|
||||
"status": "done",
|
||||
"priority": "high",
|
||||
"dependencies": [],
|
||||
"testStrategy": "1. Gate proxy model smoke test: identical behavior to current hardcoded gate (begin_session, tools/list filtering, ungating). 2. Composition test: model extending [gate, paginate] inherits both behaviors. 3. Conflict detection test: two parents intercepting same hook differently = compile-time error. 4. Discovery test: drop a .ts file in proxymodels dir, mcpctl get proxymodels shows it. 5. Existing smoke tests (proxy-pipeline.test.ts) pass unchanged after migration.",
|
||||
"subtasks": [],
|
||||
"updatedAt": "2026-02-28T03:37:04.389Z"
|
||||
"updatedAt": "2026-03-07T01:26:57.383Z"
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"version": "1.0.0",
|
||||
"lastModified": "2026-02-28T03:37:04.390Z",
|
||||
"lastModified": "2026-03-07T23:36:15.981Z",
|
||||
"taskCount": 114,
|
||||
"completedCount": 80,
|
||||
"completedCount": 96,
|
||||
"tags": [
|
||||
"master"
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user