@everystack/mcp 0.2.3 → 0.3.1
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.
- package/README.md +37 -10
- package/dist/adding-database.md +169 -0
- package/dist/admin.md +81 -0
- package/dist/auth.md +115 -0
- package/dist/aws-setup.md +276 -0
- package/dist/cli.md +108 -0
- package/dist/client-api.md +145 -0
- package/dist/core.md +196 -0
- package/dist/deployment.md +146 -0
- package/dist/events.md +87 -0
- package/dist/first-run.md +100 -0
- package/dist/getting-started.md +75 -0
- package/dist/handler-options.md +114 -0
- package/dist/images.md +93 -0
- package/dist/index.cjs +23796 -0
- package/dist/jobs.md +97 -0
- package/dist/logging.md +91 -0
- package/dist/plugins.md +68 -0
- package/dist/project-claude-md.md +103 -0
- package/dist/query-protocol.md +129 -0
- package/dist/schema-patterns.md +167 -0
- package/dist/security-device.md +99 -0
- package/dist/security.md +270 -0
- package/dist/ssr.md +82 -0
- package/dist/storage.md +63 -0
- package/dist/testing.md +118 -0
- package/package.json +11 -9
- package/src/gates/detectors/embedded-data-bundle.ts +58 -0
- package/src/gates/detectors/hand-written-migration.ts +42 -0
- package/src/gates/detectors/secret-in-public-env.ts +41 -0
- package/src/gates/engine.ts +80 -0
- package/src/gates/registry.ts +25 -0
- package/src/gates/telemetry.ts +143 -0
- package/src/gates/types.ts +70 -0
- package/src/governance/cli.ts +193 -0
- package/src/governance/grounding.ts +344 -0
- package/src/index.ts +97 -50
- package/src/prompts/claude-md.ts +92 -0
- package/src/prompts/governance-setup.ts +85 -0
- package/src/prompts/index.ts +6 -0
- package/src/prompts/new-app.ts +4 -1
- package/src/prompts/runbook.ts +77 -0
- package/src/resources/project-claude-md.md +70 -94
- package/src/tools/index.ts +6 -39
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* `governance_setup` — guide the agent to wire the everystack governance hooks
|
|
6
|
+
* into the project's `.claude/settings.json`. The server instructions tell the
|
|
7
|
+
* agent that enforcement runs via hooks; this prompt produces the exact block and
|
|
8
|
+
* the confirm-first procedure.
|
|
9
|
+
*/
|
|
10
|
+
export function registerGovernanceSetupPrompt(server: McpServer): void {
|
|
11
|
+
server.prompt(
|
|
12
|
+
'governance_setup',
|
|
13
|
+
'Install the everystack governance hooks (grounding gate + cheat gates) into .claude/settings.json. The MCP server alone does not enforce — the hooks are the teeth.',
|
|
14
|
+
{
|
|
15
|
+
projectPath: z.string().optional().describe('Absolute path to the project root'),
|
|
16
|
+
mode: z
|
|
17
|
+
.enum(['workspace', 'installed'])
|
|
18
|
+
.optional()
|
|
19
|
+
.describe('"workspace" (run from this monorepo via tsx) or "installed" (the published @everystack/mcp bin). Default: detect.'),
|
|
20
|
+
},
|
|
21
|
+
async ({ projectPath, mode }) => {
|
|
22
|
+
const cmd =
|
|
23
|
+
mode === 'workspace'
|
|
24
|
+
? 'npx tsx packages/mcp/src/index.ts'
|
|
25
|
+
: mode === 'installed'
|
|
26
|
+
? 'everystack-mcp'
|
|
27
|
+
: 'everystack-mcp';
|
|
28
|
+
const hooks = {
|
|
29
|
+
hooks: {
|
|
30
|
+
SessionStart: [{ hooks: [{ type: 'command', command: `${cmd} context` }] }],
|
|
31
|
+
PreToolUse: [{ matcher: '*', hooks: [{ type: 'command', command: `${cmd} gate` }] }],
|
|
32
|
+
PostToolUse: [
|
|
33
|
+
{ matcher: 'Read', hooks: [{ type: 'command', command: `${cmd} mark` }] },
|
|
34
|
+
{ matcher: 'Write|Edit', hooks: [{ type: 'command', command: `${cmd} validate` }] },
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
messages: [
|
|
41
|
+
{
|
|
42
|
+
role: 'user' as const,
|
|
43
|
+
content: {
|
|
44
|
+
type: 'text' as const,
|
|
45
|
+
text: [
|
|
46
|
+
`Install the everystack governance hooks for ${projectPath ? 'the project at ' + projectPath : 'this project'}.`,
|
|
47
|
+
'',
|
|
48
|
+
'## Why',
|
|
49
|
+
'',
|
|
50
|
+
'The everystack MCP server provides knowledge, but ENFORCEMENT (the grounding gate and',
|
|
51
|
+
'cheat gates) runs only when these Claude Code hooks are installed. Without them, nothing',
|
|
52
|
+
'catches off-script work (hand-written migrations, data bundled into the app, secrets behind',
|
|
53
|
+
'EXPO_PUBLIC_*).',
|
|
54
|
+
'',
|
|
55
|
+
'## Procedure (confirm-first — never silent)',
|
|
56
|
+
'',
|
|
57
|
+
'1. Read `docs/governance-setup.md` and `hooks.example.json` from the @everystack/mcp package.',
|
|
58
|
+
`2. Check whether ${projectPath ? projectPath + '/.claude/settings.json' : '.claude/settings.json'} already has these hooks (commands calling \`${cmd} gate\`).`,
|
|
59
|
+
'3. If absent, show the human the exact block below and confirm the command form before writing:',
|
|
60
|
+
' - **Workspace (this monorepo):** `npx tsx packages/mcp/src/index.ts <sub>`',
|
|
61
|
+
' - **Installed package:** `everystack-mcp <sub>` (install `@everystack/mcp`; in a hook prefer',
|
|
62
|
+
' `pnpm exec everystack-mcp <sub>` over bare `npx`, which re-resolves on every tool call).',
|
|
63
|
+
'4. Merge the `hooks` block into `.claude/settings.json` (preserve any existing `hooks`/`permissions`).',
|
|
64
|
+
'5. Remind the human: hooks run a shell command on every tool call. This is a deliberate,',
|
|
65
|
+
' security-relevant change — it is their call, not yours to make silently.',
|
|
66
|
+
'',
|
|
67
|
+
'## The block to merge',
|
|
68
|
+
'',
|
|
69
|
+
'```json',
|
|
70
|
+
JSON.stringify(hooks, null, 2),
|
|
71
|
+
'```',
|
|
72
|
+
'',
|
|
73
|
+
'## After install',
|
|
74
|
+
'',
|
|
75
|
+
'- A fresh session denies every non-Read tool until the project contract (CLAUDE.md + its',
|
|
76
|
+
' REQUIRED-READS) is read. That is the grounding gate working.',
|
|
77
|
+
'- `everystack-mcp report` summarizes what the agent tried (the telemetry sensor).',
|
|
78
|
+
].join('\n'),
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
};
|
|
83
|
+
},
|
|
84
|
+
);
|
|
85
|
+
}
|
package/src/prompts/index.ts
CHANGED
|
@@ -5,6 +5,9 @@ import { registerDesignSchemaPrompt } from './design-schema.js';
|
|
|
5
5
|
import { registerDeployPrompt } from './deploy.js';
|
|
6
6
|
import { registerDebugPrompt } from './debug.js';
|
|
7
7
|
import { registerSecurePrompt } from './secure.js';
|
|
8
|
+
import { registerGovernanceSetupPrompt } from './governance-setup.js';
|
|
9
|
+
import { registerClaudeMdPrompt } from './claude-md.js';
|
|
10
|
+
import { registerRunbookPrompt } from './runbook.js';
|
|
8
11
|
|
|
9
12
|
export function registerPrompts(server: McpServer): void {
|
|
10
13
|
registerNewAppPrompt(server);
|
|
@@ -13,4 +16,7 @@ export function registerPrompts(server: McpServer): void {
|
|
|
13
16
|
registerDeployPrompt(server);
|
|
14
17
|
registerDebugPrompt(server);
|
|
15
18
|
registerSecurePrompt(server);
|
|
19
|
+
registerGovernanceSetupPrompt(server);
|
|
20
|
+
registerClaudeMdPrompt(server);
|
|
21
|
+
registerRunbookPrompt(server);
|
|
16
22
|
}
|
package/src/prompts/new-app.ts
CHANGED
|
@@ -177,7 +177,10 @@ export function registerNewAppPrompt(server: McpServer): void {
|
|
|
177
177
|
].join('\n') : '',
|
|
178
178
|
'',
|
|
179
179
|
'## Project Documentation',
|
|
180
|
-
'
|
|
180
|
+
'Scaffold the project contract (use the claude_md prompt): read the everystack://project-claude-md',
|
|
181
|
+
'resource and write a CLAUDE.md to the project root. This file activates the grounding gate —',
|
|
182
|
+
'every later session must read it before editing — so it carries the non-negotiables the cheat',
|
|
183
|
+
'gates enforce. Keep it current as the project grows (claude_md reconciles it).',
|
|
181
184
|
`Replace {PROJECT_NAME} with "${effectiveName}", {ONE_LINE_DESCRIPTION} with "${description}",`,
|
|
182
185
|
'and {ANNOTATED_DIRECTORY_TREE} with the actual project structure created above.',
|
|
183
186
|
'',
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* `runbook` — generate or refresh docs/RUNBOOK.md, the per-app operations manual.
|
|
6
|
+
*
|
|
7
|
+
* The compiler lives in the CLI (`everystack runbook` — db:generate for docs:
|
|
8
|
+
* detection → sections keyed by the app's reality → es:gen/es:slot merge). This
|
|
9
|
+
* prompt is the thin agent layer on top: run the compiler, then fill the EMPTY
|
|
10
|
+
* slots with app-specific narrative the compiler cannot know. Generated blocks
|
|
11
|
+
* belong to the compiler — the agent never writes inside them.
|
|
12
|
+
*/
|
|
13
|
+
export function registerRunbookPrompt(server: McpServer): void {
|
|
14
|
+
server.prompt(
|
|
15
|
+
'runbook',
|
|
16
|
+
'Generate or refresh docs/RUNBOOK.md — the operations manual compiled from the app\'s detected reality (tier, Models, handlers). Runs `everystack runbook`, then fills empty slots with app narrative (confirm-first). Regenerate after the app grows or an everystack upgrade.',
|
|
17
|
+
{
|
|
18
|
+
projectPath: z.string().optional().describe('Absolute path to the project root (where docs/RUNBOOK.md lives)'),
|
|
19
|
+
},
|
|
20
|
+
async ({ projectPath }) => {
|
|
21
|
+
const root = projectPath ?? '.';
|
|
22
|
+
return {
|
|
23
|
+
messages: [
|
|
24
|
+
{
|
|
25
|
+
role: 'user' as const,
|
|
26
|
+
content: {
|
|
27
|
+
type: 'text' as const,
|
|
28
|
+
text: [
|
|
29
|
+
`Generate or refresh docs/RUNBOOK.md for the project at ${root}.`,
|
|
30
|
+
'',
|
|
31
|
+
'## What this is',
|
|
32
|
+
'',
|
|
33
|
+
'docs/RUNBOOK.md is the per-app operations manual — how to configure, extend, deploy,',
|
|
34
|
+
'monitor, and maintain THIS app. It is COMPILED, not authored: `everystack runbook`',
|
|
35
|
+
'derives it from the app\'s detected reality (installed packages → tier, Models,',
|
|
36
|
+
'handlers, crons) and regenerating after a change diffs in what\'s new. The division',
|
|
37
|
+
'of labor: CLAUDE.md is the terse contract (rules); the runbook is procedures.',
|
|
38
|
+
'',
|
|
39
|
+
'## Step 1 — run the compiler',
|
|
40
|
+
'',
|
|
41
|
+
`- If ${root}/docs/RUNBOOK.md exists, run \`everystack runbook --diff\` first and show`,
|
|
42
|
+
' the human which sections would change.',
|
|
43
|
+
'- Then run `everystack runbook` to write it. If it reports hand-edited generated',
|
|
44
|
+
' sections (a conflict), do NOT reach for --force — help the human move those words',
|
|
45
|
+
' into a slot or the Notes section first, then regenerate. --force only with their',
|
|
46
|
+
' explicit ok.',
|
|
47
|
+
'',
|
|
48
|
+
'## Step 2 — fill the EMPTY slots (and only the slots)',
|
|
49
|
+
'',
|
|
50
|
+
'The document has two kinds of content, mechanically marked:',
|
|
51
|
+
'- `<!-- es:gen section=... -->` blocks belong to the compiler. NEVER write inside one —',
|
|
52
|
+
' your words would be overwritten on the next regeneration, and the hash check flags it.',
|
|
53
|
+
'- `<!-- es:slot name=... -->` blocks are the human/agent seam and survive every',
|
|
54
|
+
' regeneration. A slot still holding its `_(Fill in: ...)_` placeholder is empty.',
|
|
55
|
+
'',
|
|
56
|
+
'For each empty slot, draft content from what you know of the project:',
|
|
57
|
+
'- `overview` — what the app is, who it serves, what an operator should know first.',
|
|
58
|
+
'- `stage-notes` — deployed URLs per stage, channel-to-stage mapping, release cadence',
|
|
59
|
+
' (read `.sst/outputs.json` or ask; do not guess URLs).',
|
|
60
|
+
'- `notes` — anything project-specific that fits nowhere else. Leave it if nothing real.',
|
|
61
|
+
'',
|
|
62
|
+
'Show the human your draft slot content and let them approve before writing — the',
|
|
63
|
+
'runbook is theirs; you assist, you do not own it.',
|
|
64
|
+
'',
|
|
65
|
+
'## Step 3 — verify',
|
|
66
|
+
'',
|
|
67
|
+
'Run `everystack runbook --check`: it must exit clean (slot edits never make it stale).',
|
|
68
|
+
'Tell the human: regenerate any time with `everystack runbook`; CI can enforce currency',
|
|
69
|
+
'with `--check`; after an everystack upgrade the diff reads as release notes for this app.',
|
|
70
|
+
].join('\n'),
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
};
|
|
75
|
+
},
|
|
76
|
+
);
|
|
77
|
+
}
|
|
@@ -2,13 +2,43 @@
|
|
|
2
2
|
|
|
3
3
|
> {ONE_LINE_DESCRIPTION}
|
|
4
4
|
|
|
5
|
+
This file is the contract for how this project is built. Read it before writing code; it
|
|
6
|
+
overrides convenience. When a rule is hard to follow, that is the signal you are about to
|
|
7
|
+
introduce drift — stop and do it the right way.
|
|
8
|
+
|
|
9
|
+
<!--
|
|
10
|
+
REQUIRED-READS: (optional) a comma-separated list of companion files that must also be
|
|
11
|
+
read before non-Read tools, e.g. `REQUIRED-READS: docs/architecture.md, db/SCHEMA.md`.
|
|
12
|
+
This CLAUDE.md is required automatically — add the line only if real companion docs exist.
|
|
13
|
+
-->
|
|
14
|
+
|
|
15
|
+
## Non-negotiables
|
|
16
|
+
|
|
17
|
+
These are enforced (everystack cheat gates) and load-bearing. Do not work around them.
|
|
18
|
+
|
|
19
|
+
- **Data lives in PostgreSQL, served through the API — never bundle data into the app.** A
|
|
20
|
+
large `.json`/`.csv` of computed data in the bundle is wrong; model it and serve it, or
|
|
21
|
+
render an empty state if it does not exist yet.
|
|
22
|
+
- **Schema and migrations are generated from Models.** Declare tables with `defineModel`
|
|
23
|
+
(in `models/`), run `everystack db:generate`. Never hand-write a SQL migration, never edit
|
|
24
|
+
the generated `db/schema.ts`. After any change, `db:generate` must be a clean no-op.
|
|
25
|
+
- **Authorization is declared, not hand-written.** Use `can()` abilities on the Model; they
|
|
26
|
+
compile to RLS + grants. Never hand-write `CREATE POLICY`/`GRANT`. RLS is required.
|
|
27
|
+
- **Reuse `@everystack/ui`.** Do not hand-roll a component that already exists there. Style
|
|
28
|
+
with classNames (light + dark), not inline `StyleSheet`.
|
|
29
|
+
- **Secrets stay server-side.** Never put a DB URL, key, or token behind an `EXPO_PUBLIC_*`
|
|
30
|
+
name — those are compiled into the client bundle forever. Use `everystack secrets`.
|
|
31
|
+
- **Apps stay thin.** Screens wire routing and UI; reusable logic lives in packages/`lib`.
|
|
32
|
+
|
|
5
33
|
## Start Here
|
|
6
34
|
|
|
35
|
+
- `models/` — `defineModel` tables (the source of truth for schema + authz)
|
|
7
36
|
- `app/` — Expo Router pages (screens, navigation, API routes)
|
|
8
37
|
- `server/` — Lambda handlers (api.ts, worker.ts, image.ts)
|
|
9
|
-
- `db/` — Drizzle schema
|
|
10
|
-
- `lib/` —
|
|
38
|
+
- `db/` — generated Drizzle schema + migrations (do not edit by hand)
|
|
39
|
+
- `lib/` — shared code (auth context, API client)
|
|
11
40
|
- `sst.config.ts` — AWS infrastructure definition
|
|
41
|
+
- `docs/RUNBOOK.md` — how to operate this app; regenerate with `everystack runbook`
|
|
12
42
|
|
|
13
43
|
## Structure
|
|
14
44
|
|
|
@@ -17,111 +47,57 @@
|
|
|
17
47
|
## Commands
|
|
18
48
|
|
|
19
49
|
```bash
|
|
20
|
-
pnpm install
|
|
21
|
-
pnpm dev
|
|
22
|
-
pnpm test
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
everystack
|
|
27
|
-
everystack
|
|
28
|
-
everystack
|
|
29
|
-
everystack
|
|
50
|
+
pnpm install # Install dependencies
|
|
51
|
+
pnpm dev # Start the Expo dev server
|
|
52
|
+
pnpm test # Run all tests (TDD)
|
|
53
|
+
everystack db:generate # Models → next migration (data + authz)
|
|
54
|
+
everystack db:migrate # Apply migrations on the deployed Lambda
|
|
55
|
+
everystack db:seed # Seed the database (dev only)
|
|
56
|
+
everystack deploy --stage dev # Deploy infrastructure (SST)
|
|
57
|
+
everystack update --channel production # OTA update (no redeploy)
|
|
58
|
+
everystack secrets set KEY "value" --stage dev # Set a server-side secret
|
|
59
|
+
everystack bundle:audit <url> # Audit a deployed bundle (weight + leaks)
|
|
30
60
|
```
|
|
31
61
|
|
|
32
62
|
## Key Principles
|
|
33
63
|
|
|
34
|
-
###
|
|
35
|
-
|
|
36
|
-
Strict mode, no exceptions. Prefer `unknown` over `any`. Explicit return types on exported functions. Named exports only (no default exports).
|
|
37
|
-
|
|
38
|
-
### Always TDD
|
|
39
|
-
|
|
40
|
-
Every feature starts with a failing test.
|
|
41
|
-
|
|
42
|
-
1. Write a failing test that describes expected behavior
|
|
43
|
-
2. Implement the minimum code to make it pass
|
|
44
|
-
3. Refactor while keeping tests green
|
|
45
|
-
|
|
46
|
-
Tests live in `__tests__/` mirroring source structure, named `{feature}.test.ts`. Run from package dir: `npx jest __tests__/path/to/test.ts`
|
|
47
|
-
|
|
48
|
-
### Platform Security Over All Else
|
|
49
|
-
|
|
50
|
-
Three layers of defense. Each is a complete security boundary:
|
|
51
|
-
|
|
52
|
-
1. **Edge (CloudFront)** — JWT signature + expiry check. Invalid tokens never reach Lambda.
|
|
53
|
-
2. **Handler (Lambda)** — `SET LOCAL ROLE` via pgSettings, RPC role gates, rowOwnership, exposedTables.
|
|
54
|
-
3. **Database (PostgreSQL)** — GRANTs + RLS policies. The single source of truth for authorization.
|
|
55
|
-
|
|
56
|
-
Even if the handler has a bug, the database enforces access. Never skip RLS. Never connect as superuser in production.
|
|
64
|
+
### Models are the source of truth (v3)
|
|
57
65
|
|
|
58
|
-
|
|
66
|
+
Declare tables with `defineModel` (`field`, `can`, relations). A package's full DB slice is a
|
|
67
|
+
`defineModule`; the app composes Modules. `everystack db:generate` compiles them to one
|
|
68
|
+
migration (schema + RLS + grants); `deriveHandlerConfig(models)` derives the API config. You
|
|
69
|
+
never hand-write migrations, RLS, or handler access-control — they are derived, so they cannot
|
|
70
|
+
drift.
|
|
59
71
|
|
|
60
|
-
|
|
72
|
+
### Security over all else
|
|
61
73
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
74
|
+
Three layers, each a complete boundary: edge (CloudFront JWT check), handler (pgSettings role +
|
|
75
|
+
ownership), and database (GRANTs + RLS — the source of truth). Even if the handler has a bug,
|
|
76
|
+
the database enforces access. Never skip RLS. Never connect as superuser in production.
|
|
65
77
|
|
|
66
|
-
###
|
|
78
|
+
### Progressive complexity
|
|
67
79
|
|
|
68
|
-
|
|
80
|
+
Each tier adds to the previous; you never rip out what you have.
|
|
81
|
+
- **V1:** Static. Expo + S3 + CloudFront + Lambda SSR + OTA. No database.
|
|
82
|
+
- **V2:** Add PostgreSQL, the API, JWT auth, admin, logging.
|
|
83
|
+
- **V3:** Add SQS workers, image processing, S3 file storage.
|
|
69
84
|
|
|
70
|
-
###
|
|
85
|
+
### Test-driven
|
|
71
86
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
## The Stack
|
|
75
|
-
|
|
76
|
-
**App:**
|
|
77
|
-
- TypeScript (strict mode)
|
|
78
|
-
- Expo + expo-router (file-based routing)
|
|
79
|
-
- React Native + react-native-web (cross-platform)
|
|
80
|
-
- @mgcrea/react-native-tailwind (Tailwind CSS styling)
|
|
81
|
-
|
|
82
|
-
**Data:**
|
|
83
|
-
- drizzle-orm + drizzle-kit (schema, queries, migrations)
|
|
84
|
-
- postgres (postgres.js driver)
|
|
85
|
-
- PostgreSQL (database)
|
|
86
|
-
|
|
87
|
-
**Infrastructure:**
|
|
88
|
-
- SST (infrastructure as code)
|
|
89
|
-
- AWS (S3, CloudFront, Lambda, RDS Aurora Serverless, SQS)
|
|
90
|
-
|
|
91
|
-
**Dev Tooling:**
|
|
92
|
-
- jest + ts-jest (testing)
|
|
93
|
-
- esbuild (Lambda bundling)
|
|
94
|
-
- pnpm (package management)
|
|
87
|
+
Every feature starts with a failing test. Tests in `__tests__/` mirroring source.
|
|
95
88
|
|
|
96
89
|
## Conventions
|
|
97
90
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
-
|
|
101
|
-
-
|
|
102
|
-
- Exports: named (no default exports)
|
|
103
|
-
- Types: PascalCase, no `I` prefix
|
|
104
|
-
- Functions: camelCase
|
|
105
|
-
|
|
106
|
-
### Git
|
|
107
|
-
|
|
108
|
-
- Conventional commits: `feat:`, `fix:`, `chore:`, `docs:`, `test:`, `refactor:`
|
|
109
|
-
- Scope optional: `feat(handler):`, `fix(client):`
|
|
110
|
-
- Tests must pass before commit
|
|
111
|
-
|
|
112
|
-
### Code
|
|
113
|
-
|
|
114
|
-
- TypeScript strict mode
|
|
115
|
-
- Prefer `unknown` over `any`
|
|
116
|
-
- Explicit return types on exported functions
|
|
117
|
-
- Prefer pure functions over classes
|
|
118
|
-
- Web Standard APIs (Request/Response)
|
|
119
|
-
- Error handling at boundaries only
|
|
91
|
+
- Package scope `@everystack/*`; files `kebab-case.ts`; named exports (no defaults); types
|
|
92
|
+
PascalCase (no `I` prefix); functions camelCase; DB columns `snake_case`.
|
|
93
|
+
- TypeScript strict; prefer `unknown` over `any`; explicit return types on exports.
|
|
94
|
+
- Conventional commits (`feat:`, `fix:`, `chore:`, `docs:`); tests pass before commit.
|
|
120
95
|
|
|
121
|
-
|
|
96
|
+
## What NOT to Do
|
|
122
97
|
|
|
123
|
-
- Don't
|
|
124
|
-
- Don't
|
|
125
|
-
- Don't
|
|
126
|
-
- Don't
|
|
127
|
-
- Don't
|
|
98
|
+
- Don't bundle large data into the app — it lives in the DB, served by the API.
|
|
99
|
+
- Don't hand-write migrations or edit `db/schema.ts` — edit the Model, run `db:generate`.
|
|
100
|
+
- Don't hand-write RLS — declare `can()` abilities.
|
|
101
|
+
- Don't hand-roll a component that exists in `@everystack/ui`; don't use inline `StyleSheet`.
|
|
102
|
+
- Don't put a secret behind `EXPO_PUBLIC_*` — that ships to the client.
|
|
103
|
+
- Don't skip RLS, skip tests, or build features beyond what's tested.
|
package/src/tools/index.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
-
import { analyzeProjectStatus } from './project-status.js';
|
|
4
|
-
import { analyzeSchema } from './schema-analyze.js';
|
|
5
|
-
import { validateProject } from './project-validate.js';
|
|
6
3
|
import { checkEnvironment } from './check-environment.js';
|
|
7
4
|
|
|
5
|
+
// NOTE (Brick 0): the legacy regex tools — project_status, schema_analyze,
|
|
6
|
+
// project_validate — are intentionally NOT registered. They predate the v3
|
|
7
|
+
// Model/Module surface and return wrong answers on Model-based apps (e.g. they
|
|
8
|
+
// report a securely-derived handler config as "all tables accessible"). They are
|
|
9
|
+
// rebuilt on @everystack/model in Brick 1 and re-registered there. Their source
|
|
10
|
+
// files remain for that rewrite to reference.
|
|
8
11
|
export function registerTools(server: McpServer): void {
|
|
9
12
|
server.tool(
|
|
10
13
|
'check_environment',
|
|
@@ -19,40 +22,4 @@ export function registerTools(server: McpServer): void {
|
|
|
19
22
|
};
|
|
20
23
|
},
|
|
21
24
|
);
|
|
22
|
-
|
|
23
|
-
server.tool(
|
|
24
|
-
'project_status',
|
|
25
|
-
'Detect the everystack tier (V1/V2/V3), installed packages, project structure, and deployment state. Run this first to understand the user\'s project.',
|
|
26
|
-
{ projectPath: z.string().describe('Absolute path to the project root (directory containing package.json)') },
|
|
27
|
-
async ({ projectPath }) => {
|
|
28
|
-
const status = analyzeProjectStatus(projectPath);
|
|
29
|
-
return {
|
|
30
|
-
content: [{ type: 'text' as const, text: JSON.stringify(status, null, 2) }],
|
|
31
|
-
};
|
|
32
|
-
},
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
server.tool(
|
|
36
|
-
'schema_analyze',
|
|
37
|
-
'Parse Drizzle schema files and cross-reference with handler configuration. Shows tables, columns, relations, and detects misconfigurations.',
|
|
38
|
-
{ projectPath: z.string().describe('Absolute path to the project root (directory containing package.json)') },
|
|
39
|
-
async ({ projectPath }) => {
|
|
40
|
-
const analysis = analyzeSchema(projectPath);
|
|
41
|
-
return {
|
|
42
|
-
content: [{ type: 'text' as const, text: JSON.stringify(analysis, null, 2) }],
|
|
43
|
-
};
|
|
44
|
-
},
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
server.tool(
|
|
48
|
-
'project_validate',
|
|
49
|
-
'Check for common mistakes, security gaps, and convention violations. Returns errors (must fix), warnings (should fix), and info (nice to fix).',
|
|
50
|
-
{ projectPath: z.string().describe('Absolute path to the project root (directory containing package.json)') },
|
|
51
|
-
async ({ projectPath }) => {
|
|
52
|
-
const report = validateProject(projectPath);
|
|
53
|
-
return {
|
|
54
|
-
content: [{ type: 'text' as const, text: JSON.stringify(report, null, 2) }],
|
|
55
|
-
};
|
|
56
|
-
},
|
|
57
|
-
);
|
|
58
25
|
}
|