create-caspian-app 0.2.0-beta.27 → 0.2.0-beta.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,6 +13,7 @@
13
13
  - When `prisma/schema.prisma` changes, follow this order: run `npx prisma migrate dev`; if the change affects seed flow or `prisma/seed.ts`, run `npx prisma generate` and then `npx prisma db seed`; then run `npx ppy generate` so the Python ORM stays aligned with the schema.
14
14
  - Reuse the existing Python database layer in `src/lib/prisma/**`; do not create a second app-owned database abstraction unless the user explicitly asks for one.
15
15
  - Treat `src/lib/prisma/__init__.py`, `src/lib/prisma/db.py`, `src/lib/prisma/models.py`, and `settings/prisma-schema.json` as generated outputs owned by `npx ppy generate`; do not create or hand-edit them manually.
16
+ - When `caspian.config.json` has `mcp: true`, treat `src/lib/mcp/mcp_server.py` as the app-owned FastMCP server and `src/lib/mcp/fastmcp.json` as the default MCP config. Use `npm run mcp` or `fastmcp run src/lib/mcp/fastmcp.json`; do not assume root `fastmcp.json` auto-discovery.
16
17
  - Keep auth policy in `src/lib/auth/auth_config.py` and keep auth bootstrap, middleware wiring, and provider registration in `main.py`.
17
18
  - Use PulsePoint and `pp.rpc(...)` as the default frontend and client-to-server contract unless the user requests another stack.
18
19
  - Treat `pp-component` on routes, layouts, and components, and `type="text/pp"` on owned PulsePoint scripts, as compiler-injected by the Python side; do not add them manually in authored templates unless the task is explicitly about runtime internals.
@@ -34,6 +35,7 @@
34
35
 
35
36
  - Keep `src/lib/` for app-owned shared code, service wrappers, and reusable helpers.
36
37
  - Reuse the generated `src/lib/prisma/` package for Python database access, but do not hand-edit files under `src/lib/prisma/`; regenerate them with `npx ppy generate` after schema changes.
38
+ - Keep app-owned MCP tools in `src/lib/mcp/mcp_server.py` and keep the default FastMCP config in `src/lib/mcp/fastmcp.json`. If those locations change, update `settings/restart-mcp.ts` and the MCP docs together.
37
39
  - Keep auth policy in `src/lib/auth/auth_config.py`. Keep auth bootstrap and middleware order changes in `main.py`.
38
40
 
39
41
  ### `public/js/main.js`
@@ -77,17 +79,20 @@
77
79
 
78
80
  - These files are the local documentation layer, not the runtime. Verify every behavior claim against the actual code that runs.
79
81
  - Use this verification order:
80
- 1. `caspian.config.json`, then `main.py`, `src/lib/**`, `public/js/**`, `prisma/**`, `src/app/**`
81
- 2. `.venv/Lib/site-packages/casp/**`
82
- 3. the markdown file being edited
82
+ 1. `caspian.config.json`, then `main.py`, `src/lib/**`, `public/js/**`, `prisma/**`, `src/app/**`
83
+ 2. `.venv/Lib/site-packages/casp/**`
84
+ 3. the markdown file being edited
83
85
  - Keep repo-specific facts accurate when they matter:
84
- - `caspian.config.json` is the first config file to read for enabled workspace features and scan directories
85
- - this workspace already has `src/lib/prisma/**`
86
- - auth policy lives in `src/lib/auth/auth_config.py`
87
- - PulsePoint runtime lives in `public/js/pp-reactive-v2.js`
88
- - `pp-component` is injected by the Python render pipeline, and `main.py` rewrites authored body scripts to `type="text/pp"`; authored route, layout, and component templates should not add those attributes manually
89
- - route, layout, and component templates must keep a single top-level lowercase HTML root for `pp-component` injection, with any owned plain `<script>` kept inside that same root
90
- - dynamic route params are passed to `page()` as a single positional `dict`
91
- - `layout()` is sync-only in the installed runtime
92
- - `StateManager` persistence depends on `request.state.session`, which is not bridged from `request.session` in the current `main.py`
93
- - Keep `index.md` and cross-links aligned when adding or changing pages.
86
+ - `caspian.config.json` is the first config file to read for enabled workspace features and scan directories
87
+ - this workspace already has `src/lib/prisma/**`
88
+ - this workspace's app-owned FastMCP server lives in `src/lib/mcp/mcp_server.py`
89
+ - the default FastMCP config lives in `src/lib/mcp/fastmcp.json`
90
+ - `package.json` starts MCP through `npm run mcp`, which runs `settings/restart-mcp.ts`; manual FastMCP runs should pass the explicit nested config path because root auto-discovery does not find it
91
+ - auth policy lives in `src/lib/auth/auth_config.py`
92
+ - PulsePoint runtime lives in `public/js/pp-reactive-v2.js`
93
+ - `pp-component` is injected by the Python render pipeline, and `main.py` rewrites authored body scripts to `type="text/pp"`; authored route, layout, and component templates should not add those attributes manually
94
+ - route, layout, and component templates must keep a single top-level lowercase HTML root for `pp-component` injection, with any owned plain `<script>` kept inside that same root
95
+ - dynamic route params are passed to `page()` as a single positional `dict`
96
+ - `layout()` is sync-only in the installed runtime
97
+ - `StateManager` persistence depends on `request.state.session`, which is not bridged from `request.session` in the current `main.py`
98
+ - Keep `index.md` and cross-links aligned when adding or changing pages.
package/dist/AGENTS.md CHANGED
@@ -39,11 +39,13 @@ Before making feature, tooling, or scaffolding decisions, read `caspian.config.j
39
39
  - App-level auth policy lives in `src/lib/auth/auth_config.py`.
40
40
  - `main.py` applies auth settings with `configure_auth(build_auth_settings())` and registers `GithubProvider()` plus `GoogleProvider()`.
41
41
  - This workspace already has an app-owned Python database layer in `src/lib/prisma/`.
42
+ - This workspace now has an app-owned FastMCP server at `src/lib/mcp/mcp_server.py`, with `src/lib/mcp/fastmcp.json` as the default MCP server spec.
43
+ - `package.json` starts MCP through `npm run mcp`, which runs `settings/restart-mcp.ts` and prefers `src/lib/mcp/fastmcp.json` before legacy root configs. Direct FastMCP runs should pass the explicit nested config path.
42
44
  - Reuse `src/lib/prisma/prisma`, `PrismaClient`, generated models, and helper types instead of creating a second Python database abstraction.
43
45
  - Prisma schema source of truth is `prisma/schema.prisma`.
44
46
  - The schema-change workflow in this workspace is: `npx prisma migrate dev`; if seed flow or `prisma/seed.ts` is involved, run `npx prisma generate` and then `npx prisma db seed`; then run `npx ppy generate`.
45
47
  - `npx ppy generate` owns `src/lib/prisma/__init__.py`, `src/lib/prisma/db.py`, `src/lib/prisma/models.py`, and `settings/prisma-schema.json`; do not hand-edit those generated files.
46
- - `caspian.config.json` is the first config file to check for enabled workspace features. In the current workspace it sets `backendOnly: false`, `tailwindcss: true`, `mcp: false`, `prisma: true`, `typescript: false`, and `componentScanDirs: ["src"]`.
48
+ - `caspian.config.json` is the first config file to check for enabled workspace features. In the current workspace it sets `backendOnly: false`, `tailwindcss: true`, `mcp: true`, `prisma: true`, `typescript: false`, and `componentScanDirs: ["src"]`.
47
49
  - PulsePoint runtime code is shipped in `public/js/pp-reactive-v2.js` and loaded from `public/js/main.js`.
48
50
  - `pp-component` is injected by the Python render pipeline onto page, layout, and component roots; authored route and component templates should not add it manually.
49
51
  - `main.py` runs `transform_scripts(...)`, so authored body `<script>` tags are rewritten to `<script type="text/pp">` in rendered HTML; route, layout, and component templates should write plain `<script>` in source.
@@ -60,17 +62,18 @@ Before making feature, tooling, or scaffolding decisions, read `caspian.config.j
60
62
 
61
63
  Use this map before making changes.
62
64
 
63
- | Task area | Read first | Verify against |
64
- | --- | --- | --- |
65
- | Project layout and file placement | `node_modules/caspian-utils/dist/docs/index.md`, `node_modules/caspian-utils/dist/docs/project-structure.md` | current workspace tree |
66
- | Feature availability and tooling switches | `caspian.config.json` | current workspace tree, `main.py`, `prisma/**`, `public/js/**` |
67
- | Routing, layouts, metadata | `node_modules/caspian-utils/dist/docs/routing.md` | `main.py`, `.venv/Lib/site-packages/casp/layout.py` |
68
- | Auth, sessions, RBAC, providers | `node_modules/caspian-utils/dist/docs/auth.md` | `src/lib/auth/auth_config.py`, `main.py`, `.venv/Lib/site-packages/casp/auth.py` |
69
- | RPC, data loading, streaming, uploads | `node_modules/caspian-utils/dist/docs/fetch-data.md`, `node_modules/caspian-utils/dist/docs/pulsepoint.md` | `.venv/Lib/site-packages/casp/rpc.py`, `public/js/pp-reactive-v2.js`, `main.py` |
70
- | Server state | `node_modules/caspian-utils/dist/docs/state.md` | `.venv/Lib/site-packages/casp/state_manager.py`, `main.py` |
71
- | Page caching | `node_modules/caspian-utils/dist/docs/cache.md` | `.venv/Lib/site-packages/casp/cache_handler.py`, `main.py` |
72
- | Validation | `node_modules/caspian-utils/dist/docs/validation.md` | `.venv/Lib/site-packages/casp/validate.py` |
73
- | Database and seed flow | `node_modules/caspian-utils/dist/docs/database.md` | `prisma/schema.prisma`, `prisma/seed.ts`, `src/lib/prisma/**` |
65
+ | Task area | Read first | Verify against |
66
+ | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------- |
67
+ | Project layout and file placement | `node_modules/caspian-utils/dist/docs/index.md`, `node_modules/caspian-utils/dist/docs/project-structure.md` | current workspace tree |
68
+ | Feature availability and tooling switches | `caspian.config.json` | current workspace tree, `main.py`, `prisma/**`, `public/js/**` |
69
+ | MCP server layout and launch flow | `node_modules/caspian-utils/dist/docs/mcp.md` | `settings/restart-mcp.ts`, `package.json`, `src/lib/mcp/**` |
70
+ | Routing, layouts, metadata | `node_modules/caspian-utils/dist/docs/routing.md` | `main.py`, `.venv/Lib/site-packages/casp/layout.py` |
71
+ | Auth, sessions, RBAC, providers | `node_modules/caspian-utils/dist/docs/auth.md` | `src/lib/auth/auth_config.py`, `main.py`, `.venv/Lib/site-packages/casp/auth.py` |
72
+ | RPC, data loading, streaming, uploads | `node_modules/caspian-utils/dist/docs/fetch-data.md`, `node_modules/caspian-utils/dist/docs/pulsepoint.md` | `.venv/Lib/site-packages/casp/rpc.py`, `public/js/pp-reactive-v2.js`, `main.py` |
73
+ | Server state | `node_modules/caspian-utils/dist/docs/state.md` | `.venv/Lib/site-packages/casp/state_manager.py`, `main.py` |
74
+ | Page caching | `node_modules/caspian-utils/dist/docs/cache.md` | `.venv/Lib/site-packages/casp/cache_handler.py`, `main.py` |
75
+ | Validation | `node_modules/caspian-utils/dist/docs/validation.md` | `.venv/Lib/site-packages/casp/validate.py` |
76
+ | Database and seed flow | `node_modules/caspian-utils/dist/docs/database.md` | `prisma/schema.prisma`, `prisma/seed.ts`, `src/lib/prisma/**` |
74
77
 
75
78
  ## Editing Rules
76
79
 
@@ -82,6 +85,7 @@ Use this map before making changes.
82
85
  - When `prisma/schema.prisma` changes, run `npx prisma migrate dev` first. If seed flow or `prisma/seed.ts` is involved, run `npx prisma generate` and then `npx prisma db seed`. After that, run `npx ppy generate` so the Python ORM layer and `settings/prisma-schema.json` stay aligned.
83
86
  - Keep auth policy in `src/lib/auth/auth_config.py`.
84
87
  - Keep auth bootstrap, middleware ordering, provider wiring, and router behavior in `main.py`.
88
+ - When MCP is enabled, keep the app-owned FastMCP server in `src/lib/mcp/mcp_server.py` and the default config in `src/lib/mcp/fastmcp.json`. If those paths move, update `settings/restart-mcp.ts` and the MCP docs together.
85
89
  - Use PulsePoint and `pp.rpc(...)` as the default frontend and browser-to-server contract unless the user explicitly wants another stack.
86
90
  - Treat `pp-component` as a framework-owned attribute on authored templates. Document it, but do not manually add it in normal route or component HTML.
87
91
  - Treat `type="text/pp"` on PulsePoint scripts as a render-time attribute too. In authored route, layout, and component HTML, write plain `<script>` and let Caspian rewrite it.
@@ -96,6 +100,7 @@ Use this map before making changes.
96
100
  The packaged docs in this workspace are already mostly aligned with the installed runtime, but keep these repo-specific clarifications in mind:
97
101
 
98
102
  - `database.md` is the source doc for the Prisma and Python ORM workflow in this repo: schema changes go through `npx prisma migrate dev`, optional `npx prisma generate` plus `npx prisma db seed`, then `npx ppy generate`, and generated ORM files under `src/lib/prisma/` plus `settings/prisma-schema.json` are not hand-edited.
103
+ - `mcp.md` is the source doc for the nested FastMCP config path, the app-owned MCP server location, direct FastMCP command usage, and the workspace runner discovery order.
99
104
  - `state.md` is correct to warn that cross-request persistence depends on `request.state.session`, which is not bridged in the current `main.py`.
100
105
  - `routing.md`, `components.md`, `auth.md`, `fetch-data.md`, `cache.md`, `pulsepoint.md`, and `validation.md` should continue to be validated against the installed `casp` package before any behavior claims are changed.
101
106
 
@@ -0,0 +1,148 @@
1
+ import { existsSync } from "fs";
2
+ import { join } from "path";
3
+ import caspianConfig from "../caspian.config.json";
4
+ import { createRestartableProcess, onExit } from "./utils.js";
5
+
6
+ const projectRoot = process.cwd();
7
+ const localFastMcp =
8
+ process.platform === "win32"
9
+ ? join(projectRoot, ".venv", "Scripts", "fastmcp.exe")
10
+ : join(projectRoot, ".venv", "bin", "fastmcp");
11
+
12
+ const fastMcpCommand = existsSync(localFastMcp) ? localFastMcp : "fastmcp";
13
+
14
+ const suppressedLinePatterns = [
15
+ /AuthlibDeprecationWarning/,
16
+ /^It will be compatible before version 2\.0\.0\.$/,
17
+ /^from authlib\.jose import /,
18
+ /^INFO:\s+Started server process/,
19
+ /^INFO:\s+Waiting for application startup\.$/,
20
+ /^INFO:\s+Application startup complete\.$/,
21
+ ];
22
+
23
+ function getServerSpec(): string | null {
24
+ const explicitSpec = process.env.MCP_SERVER_SPEC?.trim();
25
+ if (explicitSpec) {
26
+ return explicitSpec;
27
+ }
28
+
29
+ const defaultSpecs = ["src/lib/mcp/fastmcp.json", "fastmcp.json", "mcp.json"];
30
+ for (const relativeSpec of defaultSpecs) {
31
+ if (existsSync(join(projectRoot, relativeSpec))) {
32
+ return relativeSpec;
33
+ }
34
+ }
35
+
36
+ return null;
37
+ }
38
+
39
+ function buildArgs(serverSpec: string): string[] {
40
+ const args = ["run", serverSpec, "--no-banner"];
41
+ const transport = process.env.MCP_TRANSPORT?.trim();
42
+ const host = process.env.MCP_HOST?.trim();
43
+ const port = process.env.MCP_PORT?.trim();
44
+ const path = process.env.MCP_PATH?.trim();
45
+ const logLevel = process.env.MCP_LOG_LEVEL?.trim();
46
+
47
+ if (transport) args.push("--transport", transport);
48
+ if (host) args.push("--host", host);
49
+ if (port) args.push("--port", port);
50
+ if (path) args.push("--path", path);
51
+ if (logLevel) args.push("--log-level", logLevel);
52
+
53
+ return args;
54
+ }
55
+
56
+ function createLineHandler(handleLine: (line: string) => void) {
57
+ let buffer = "";
58
+
59
+ return (chunk: Buffer) => {
60
+ buffer += chunk.toString();
61
+ const lines = buffer.split(/\r?\n/);
62
+ buffer = lines.pop() ?? "";
63
+
64
+ for (const line of lines) {
65
+ handleLine(line);
66
+ }
67
+ };
68
+ }
69
+
70
+ function createMcpOutputHandler() {
71
+ let waitingForReadyUrl = false;
72
+ let readyReported = false;
73
+
74
+ return (line: string) => {
75
+ const trimmed = line.trim();
76
+ if (!trimmed) {
77
+ return;
78
+ }
79
+
80
+ if (suppressedLinePatterns.some((pattern) => pattern.test(trimmed))) {
81
+ return;
82
+ }
83
+
84
+ if (trimmed.includes("Starting MCP server")) {
85
+ waitingForReadyUrl = true;
86
+ return;
87
+ }
88
+
89
+ if (trimmed.includes("transport '") && trimmed.endsWith(" on")) {
90
+ waitingForReadyUrl = true;
91
+ return;
92
+ }
93
+
94
+ const urlMatch = trimmed.match(/https?:\/\/\S+/);
95
+ if (
96
+ urlMatch &&
97
+ (waitingForReadyUrl || trimmed.includes("Uvicorn running on"))
98
+ ) {
99
+ waitingForReadyUrl = false;
100
+ if (!readyReported) {
101
+ console.log(`[mcp] Ready at ${urlMatch[0]}`);
102
+ readyReported = true;
103
+ }
104
+ return;
105
+ }
106
+
107
+ if (trimmed.startsWith("INFO:")) {
108
+ return;
109
+ }
110
+
111
+ waitingForReadyUrl = false;
112
+
113
+ if (/traceback|exception|error/i.test(trimmed)) {
114
+ console.error(`[mcp] ${trimmed}`);
115
+ return;
116
+ }
117
+
118
+ console.log(`[mcp] ${trimmed}`);
119
+ };
120
+ }
121
+
122
+ if (!caspianConfig.mcp) {
123
+ console.log("[mcp] Disabled in caspian.config.json, skipping MCP startup.");
124
+ process.exit(0);
125
+ }
126
+
127
+ const serverSpec = getServerSpec();
128
+
129
+ if (!serverSpec) {
130
+ console.log(
131
+ "[mcp] Enabled, but no FastMCP server spec was found. Create src/lib/mcp/fastmcp.json or set MCP_SERVER_SPEC to a FastMCP config, file, or URL.",
132
+ );
133
+ process.exit(0);
134
+ }
135
+
136
+ const handleMcpOutput = createMcpOutputHandler();
137
+
138
+ const runner = createRestartableProcess({
139
+ name: "mcp",
140
+ cmd: fastMcpCommand,
141
+ args: buildArgs(serverSpec),
142
+ startMessage: "[mcp] Starting MCP server...",
143
+ onStdout: createLineHandler(handleMcpOutput),
144
+ onStderr: createLineHandler(handleMcpOutput),
145
+ });
146
+
147
+ runner.start();
148
+ onExit(() => runner.stop());
@@ -40,7 +40,7 @@ export function createSrcWatcher(
40
40
  logPrefix?: string;
41
41
  usePolling?: boolean;
42
42
  interval?: number;
43
- }
43
+ },
44
44
  ): FSWatcher {
45
45
  const {
46
46
  exts,
@@ -87,7 +87,7 @@ export class DebouncedWorker {
87
87
  constructor(
88
88
  private work: () => Promise<void> | void,
89
89
  private debounceMs = 350,
90
- private name = "worker"
90
+ private name = "worker",
91
91
  ) {}
92
92
 
93
93
  schedule(reason?: string) {
@@ -124,6 +124,7 @@ export function createRestartableProcess(spec: {
124
124
  cmd: string;
125
125
  args?: string[];
126
126
  stdio?: "inherit" | [any, any, any];
127
+ startMessage?: string;
127
128
  gracefulSignal?: NodeJS.Signals;
128
129
  forceKillAfterMs?: number;
129
130
  windowsKillTree?: boolean;
@@ -135,6 +136,7 @@ export function createRestartableProcess(spec: {
135
136
  cmd,
136
137
  args = [],
137
138
  stdio = ["ignore", "pipe", "pipe"],
139
+ startMessage,
138
140
  gracefulSignal = "SIGINT",
139
141
  forceKillAfterMs = 2000,
140
142
  windowsKillTree = true,
@@ -145,7 +147,9 @@ export function createRestartableProcess(spec: {
145
147
  let child: ChildProcess | null = null;
146
148
 
147
149
  function start() {
148
- console.log(`[${name}] Starting: ${cmd} ${args.join(" ")}`.trim());
150
+ console.log(
151
+ startMessage ?? `[${name}] Starting: ${cmd} ${args.join(" ")}`.trim(),
152
+ );
149
153
  child = spawn(cmd, args, { stdio, windowsHide: true });
150
154
 
151
155
  child.stdout?.on("data", (buf: Buffer) => {
@@ -172,7 +176,7 @@ export function createRestartableProcess(spec: {
172
176
  function killOnWindows(pid: number): Promise<void> {
173
177
  return new Promise((resolve) => {
174
178
  const cp = execFile("taskkill", ["/F", "/T", "/PID", String(pid)], () =>
175
- resolve()
179
+ resolve(),
176
180
  );
177
181
  cp.on("error", () => resolve());
178
182
  });
@@ -0,0 +1,15 @@
1
+ {
2
+ "$schema": "https://gofastmcp.com/public/schemas/fastmcp.json/v1.json",
3
+ "source": {
4
+ "type": "filesystem",
5
+ "path": "src/lib/mcp/mcp_server.py",
6
+ "entrypoint": "mcp"
7
+ },
8
+ "deployment": {
9
+ "transport": "streamable-http",
10
+ "host": "127.0.0.1",
11
+ "port": 5101,
12
+ "path": "/mcp",
13
+ "log_level": "INFO"
14
+ }
15
+ }
@@ -0,0 +1,91 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from pathlib import Path
5
+ from typing import Any, Literal
6
+
7
+ from fastmcp import FastMCP
8
+
9
+
10
+ PROJECT_ROOT = Path(__file__).resolve().parents[3]
11
+ CASPIAN_CONFIG_PATH = PROJECT_ROOT / "caspian.config.json"
12
+ PACKAGE_JSON_PATH = PROJECT_ROOT / "package.json"
13
+ FILES_LIST_PATH = PROJECT_ROOT / "settings" / "files-list.json"
14
+ COMPONENT_MAP_PATH = PROJECT_ROOT / "settings" / "component-map.json"
15
+
16
+
17
+ mcp = FastMCP(
18
+ name="Mapka MCP",
19
+ instructions=(
20
+ "Read-only workspace metadata for the Mapka Caspian application. "
21
+ "Use these tools for project configuration, generated file inventory, and component discovery."
22
+ ),
23
+ )
24
+
25
+
26
+ def _load_json(path: Path, fallback: Any) -> Any:
27
+ if not path.exists():
28
+ return fallback
29
+
30
+ with path.open("r", encoding="utf-8") as handle:
31
+ return json.load(handle)
32
+
33
+
34
+ def _normalize_paths(paths: list[str]) -> list[str]:
35
+ return [item.removeprefix("./").replace("\\", "/") for item in paths]
36
+
37
+
38
+ @mcp.tool
39
+ def project_info() -> dict[str, Any]:
40
+ """Return the core Caspian and package metadata for this workspace."""
41
+
42
+ config = _load_json(CASPIAN_CONFIG_PATH, {})
43
+ package = _load_json(PACKAGE_JSON_PATH, {})
44
+
45
+ return {
46
+ "projectName": config.get("projectName") or package.get("name") or PROJECT_ROOT.name,
47
+ "projectRoot": str(PROJECT_ROOT),
48
+ "packageVersion": package.get("version"),
49
+ "caspianVersion": config.get("version"),
50
+ "browserSyncTarget": config.get("bsTarget"),
51
+ "featureFlags": {
52
+ "backendOnly": config.get("backendOnly"),
53
+ "tailwindcss": config.get("tailwindcss"),
54
+ "mcp": config.get("mcp"),
55
+ "prisma": config.get("prisma"),
56
+ "typescript": config.get("typescript"),
57
+ },
58
+ "componentScanDirs": config.get("componentScanDirs", []),
59
+ }
60
+
61
+
62
+ @mcp.tool
63
+ def workspace_files(kind: Literal["all", "app", "public"] = "all") -> dict[str, Any]:
64
+ """Return the generated workspace file inventory, optionally filtered by area."""
65
+
66
+ files = _normalize_paths(_load_json(FILES_LIST_PATH, []))
67
+
68
+ if kind == "app":
69
+ selected = [path for path in files if path.startswith("src/app/")]
70
+ elif kind == "public":
71
+ selected = [path for path in files if path.startswith("public/")]
72
+ else:
73
+ selected = files
74
+
75
+ return {
76
+ "kind": kind,
77
+ "count": len(selected),
78
+ "files": selected,
79
+ }
80
+
81
+
82
+ @mcp.tool
83
+ def component_inventory() -> dict[str, Any]:
84
+ """Return the latest generated component inventory for the workspace."""
85
+
86
+ components = _load_json(COMPONENT_MAP_PATH, [])
87
+
88
+ return {
89
+ "count": len(components),
90
+ "components": components,
91
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-caspian-app",
3
- "version": "0.2.0-beta.27",
3
+ "version": "0.2.0-beta.28",
4
4
  "description": "Scaffold a new Caspian project (FastAPI-powered reactive Python framework).",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",