@terreno/mcp 57.21.0 → 58.0.0-beta.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/CHANGELOG.md +43 -0
- package/README.md +57 -3
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +17 -16
- package/dist/bootstrap.js.map +1 -1
- package/dist/docs/guidelines/admin-frontend/guidelines/core.md +6 -5
- package/dist/docs/guidelines/ui/guidelines/core.md +1 -1
- package/dist/docs/prompts/debug.md +6 -4
- package/dist/docs/prompts/screen.md +11 -17
- package/dist/docs/resources/overview.md +5 -3
- package/dist/docs/resources/patterns.md +157 -238
- package/dist/docs/resources/syncdb.md +44 -16
- package/dist/docs/templates/bootstrap/CLAUDE.template.md +2 -2
- package/dist/docs/templates/bootstrap/cursorrules.template.md +7 -5
- package/dist/docs/templates/bootstrap/frontend/app/(tabs)/profile.template.tsx +8 -12
- package/dist/docs/templates/bootstrap/frontend/app/_layout.template.tsx +75 -52
- package/dist/docs/templates/bootstrap/frontend/app/login.template.tsx +46 -108
- package/dist/docs/templates/bootstrap/frontend/app/signup.template.tsx +53 -0
- package/dist/docs/templates/bootstrap/frontend/lib/betterAuth.template.md +18 -0
- package/dist/docs/templates/bootstrap/frontend/store/apiClient.template.md +33 -0
- package/dist/docs/templates/bootstrap/frontend/store/apiSdk.template.md +76 -0
- package/dist/docs/templates/bootstrap/frontend/store/syncdb.template.md +56 -0
- package/dist/docs/templates/bootstrap/frontend/utils/index.template.md +0 -4
- package/dist/docs/upgrades/58.0.0-beta.1.md +504 -0
- package/dist/docs/upgrades/58.0.0.md +495 -4
- package/dist/docs/versioned/next/README.md +2 -2
- package/dist/docs/versioned/next/approval-rubric.md +2 -2
- package/dist/docs/versioned/next/explanation/admin-interface.md +6 -5
- package/dist/docs/versioned/next/explanation/admin-plugin-frontend.md +1 -1
- package/dist/docs/versioned/next/explanation/ai-workflows.md +5 -3
- package/dist/docs/versioned/next/explanation/announcements/rtk-deprecation.md +16 -11
- package/dist/docs/versioned/next/explanation/authentication.md +62 -43
- package/dist/docs/versioned/next/explanation/dependency-management.md +1 -1
- package/dist/docs/versioned/next/explanation/deployment-baseline.md +1 -1
- package/dist/docs/versioned/next/explanation/example-coverage.md +2 -2
- package/dist/docs/versioned/next/explanation/explicit-any-policy.md +5 -6
- package/dist/docs/versioned/next/explanation/gcp-hosting-architecture.md +1 -1
- package/dist/docs/versioned/next/explanation/local-first-data.md +11 -9
- package/dist/docs/versioned/next/explanation/model-router-actions.md +1 -1
- package/dist/docs/versioned/next/explanation/modular-api-design.md +2 -2
- package/dist/docs/versioned/next/explanation/no-barrel-imports.md +5 -5
- package/dist/docs/versioned/next/explanation/roadmap-seed-issues.md +4 -3
- package/dist/docs/versioned/next/explanation/source-rules.md +2 -2
- package/dist/docs/versioned/next/explanation/typescript-configuration.md +2 -4
- package/dist/docs/versioned/next/explanation/versioning-policy.md +3 -3
- package/dist/docs/versioned/next/how-to/README.md +3 -2
- package/dist/docs/versioned/next/how-to/add-feature-flags.md +50 -25
- package/dist/docs/versioned/next/how-to/add-organizations.md +2 -1
- package/dist/docs/versioned/next/how-to/admin-custom-home.md +8 -2
- package/dist/docs/versioned/next/how-to/admin-custom-widget.md +0 -1
- package/dist/docs/versioned/next/how-to/agent-ui-asks.md +6 -6
- package/dist/docs/versioned/next/how-to/build-admin-screens.md +10 -8
- package/dist/docs/versioned/next/how-to/build-for-web.md +1 -1
- package/dist/docs/versioned/next/how-to/call-external-apis.md +2 -2
- package/dist/docs/versioned/next/how-to/circleci.md +12 -6
- package/dist/docs/versioned/next/how-to/configure-better-auth.md +114 -60
- package/dist/docs/versioned/next/how-to/connect-mcp-service-token.md +10 -4
- package/dist/docs/versioned/next/how-to/create-a-terreno-app.md +14 -2
- package/dist/docs/versioned/next/how-to/debug-with-mcp.md +8 -13
- package/dist/docs/versioned/next/how-to/expose-mcp-tools.md +15 -4
- package/dist/docs/versioned/next/how-to/generate-the-client-sdk.md +33 -0
- package/dist/docs/versioned/next/how-to/github-actions-ci.md +2 -2
- package/dist/docs/versioned/next/how-to/in-app-notifications.md +1 -1
- package/dist/docs/versioned/next/how-to/migrate-rtk-to-syncdb.md +318 -447
- package/dist/docs/versioned/next/how-to/password-reset.md +1 -1
- package/dist/docs/versioned/next/how-to/product-announcements.md +6 -3
- package/dist/docs/versioned/next/how-to/rate-limiting.md +38 -16
- package/dist/docs/versioned/next/how-to/run-mongodb-migrations.md +19 -0
- package/dist/docs/versioned/next/how-to/run-tests-locally.md +2 -3
- package/dist/docs/versioned/next/how-to/set-up-social-login.md +1 -1
- package/dist/docs/versioned/next/how-to/set-up-terreno-mcp.md +2 -2
- package/dist/docs/versioned/next/how-to/track-upstream-expo.md +1 -1
- package/dist/docs/versioned/next/how-to/upgrade-banner.md +5 -3
- package/dist/docs/versioned/next/how-to/upgrade-terreno.md +5 -5
- package/dist/docs/versioned/next/how-to/use-syncdb-correctly.md +1 -1
- package/dist/docs/versioned/next/how-to/websocket-integration.md +113 -402
- package/dist/docs/versioned/next/implementationPlans/b2b-platform-program.md +1 -1
- package/dist/docs/versioned/next/implementationPlans/migrate-admin-to-syncdb.md +5 -0
- package/dist/docs/versioned/next/implementationPlans/native-module-baseline.md +29 -5
- package/dist/docs/versioned/next/implementationPlans/remove-legacy-realtime.md +1 -1
- package/dist/docs/versioned/next/implementationPlans/remove-rtk.md +185 -0
- package/dist/docs/versioned/next/reference/README.md +1 -1
- package/dist/docs/versioned/next/reference/admin-frontend.md +85 -70
- package/dist/docs/versioned/next/reference/admin-spa.md +10 -4
- package/dist/docs/versioned/next/reference/ai.md +36 -4
- package/dist/docs/versioned/next/reference/announcements.md +3 -3
- package/dist/docs/versioned/next/reference/api.md +39 -24
- package/dist/docs/versioned/next/reference/cli.md +3 -4
- package/dist/docs/versioned/next/reference/environment-variables.md +16 -16
- package/dist/docs/versioned/next/reference/feature-flags.md +48 -7
- package/dist/docs/versioned/next/reference/jobs.md +2 -2
- package/dist/docs/versioned/next/reference/legacy/rtk.md +25 -600
- package/dist/docs/versioned/next/reference/mcp-server.md +441 -1158
- package/dist/docs/versioned/next/reference/syncdb.md +426 -16
- package/dist/docs/versioned/next/reference/test.md +28 -3
- package/dist/docs/versioned/next/reference/ui.md +132 -19
- package/dist/docs/versioned/next/tasks/native-module-baseline.md +8 -4
- package/dist/docs/versioned/next/tasks/rate-limiting.md +9 -2
- package/dist/docs/versioned/next/tasks/remove-legacy-realtime.md +5 -5
- package/dist/docs/versioned/next/tasks/remove-rtk.md +155 -0
- package/dist/local/localTools.d.ts.map +1 -1
- package/dist/local/localTools.js +3 -54
- package/dist/local/localTools.js.map +1 -1
- package/dist/local/tools/runtime.d.ts +0 -21
- package/dist/local/tools/runtime.d.ts.map +1 -1
- package/dist/local/tools/runtime.js +0 -176
- package/dist/local/tools/runtime.js.map +1 -1
- package/dist/local/tools/syncDb.d.ts +0 -11
- package/dist/local/tools/syncDb.d.ts.map +1 -1
- package/dist/local/tools/syncDb.js +1 -5
- package/dist/local/tools/syncDb.js.map +1 -1
- package/dist/packageGuidelines.d.ts +3 -2
- package/dist/packageGuidelines.d.ts.map +1 -1
- package/dist/packageGuidelines.js +4 -11
- package/dist/packageGuidelines.js.map +1 -1
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +17 -18
- package/dist/prompts.js.map +1 -1
- package/dist/resources.d.ts.map +1 -1
- package/dist/resources.js +1 -8
- package/dist/resources.js.map +1 -1
- package/dist/search/chunker.d.ts +1 -1
- package/dist/search/chunker.d.ts.map +1 -1
- package/dist/search/inferPackages.d.ts +1 -1
- package/dist/search/inferPackages.js +5 -5
- package/dist/search/inferPackages.js.map +1 -1
- package/dist/tools.d.ts +6 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +126 -119
- package/dist/tools.js.map +1 -1
- package/package.json +6 -6
- package/src/docs/guidelines/admin-frontend/guidelines/core.md +6 -5
- package/src/docs/guidelines/ui/guidelines/core.md +1 -1
- package/src/docs/prompts/debug.md +6 -4
- package/src/docs/prompts/screen.md +11 -17
- package/src/docs/resources/overview.md +5 -3
- package/src/docs/resources/patterns.md +157 -238
- package/src/docs/resources/syncdb.md +44 -16
- package/src/docs/templates/bootstrap/CLAUDE.template.md +2 -2
- package/src/docs/templates/bootstrap/cursorrules.template.md +7 -5
- package/src/docs/templates/bootstrap/frontend/app/(tabs)/profile.template.tsx +8 -12
- package/src/docs/templates/bootstrap/frontend/app/_layout.template.tsx +75 -52
- package/src/docs/templates/bootstrap/frontend/app/login.template.tsx +46 -108
- package/src/docs/templates/bootstrap/frontend/app/signup.template.tsx +53 -0
- package/src/docs/templates/bootstrap/frontend/lib/betterAuth.template.md +18 -0
- package/src/docs/templates/bootstrap/frontend/store/apiClient.template.md +33 -0
- package/src/docs/templates/bootstrap/frontend/store/apiSdk.template.md +76 -0
- package/src/docs/templates/bootstrap/frontend/store/syncdb.template.md +56 -0
- package/src/docs/templates/bootstrap/frontend/utils/index.template.md +0 -4
- package/src/docs/upgrades/58.0.0-beta.1.md +504 -0
- package/src/docs/upgrades/58.0.0.md +495 -4
- package/src/docs/versioned/next/README.md +2 -2
- package/src/docs/versioned/next/approval-rubric.md +2 -2
- package/src/docs/versioned/next/explanation/admin-interface.md +6 -5
- package/src/docs/versioned/next/explanation/admin-plugin-frontend.md +1 -1
- package/src/docs/versioned/next/explanation/ai-workflows.md +5 -3
- package/src/docs/versioned/next/explanation/announcements/rtk-deprecation.md +16 -11
- package/src/docs/versioned/next/explanation/authentication.md +62 -43
- package/src/docs/versioned/next/explanation/dependency-management.md +1 -1
- package/src/docs/versioned/next/explanation/deployment-baseline.md +1 -1
- package/src/docs/versioned/next/explanation/example-coverage.md +2 -2
- package/src/docs/versioned/next/explanation/explicit-any-policy.md +5 -6
- package/src/docs/versioned/next/explanation/gcp-hosting-architecture.md +1 -1
- package/src/docs/versioned/next/explanation/local-first-data.md +11 -9
- package/src/docs/versioned/next/explanation/model-router-actions.md +1 -1
- package/src/docs/versioned/next/explanation/modular-api-design.md +2 -2
- package/src/docs/versioned/next/explanation/no-barrel-imports.md +5 -5
- package/src/docs/versioned/next/explanation/roadmap-seed-issues.md +4 -3
- package/src/docs/versioned/next/explanation/source-rules.md +2 -2
- package/src/docs/versioned/next/explanation/typescript-configuration.md +2 -4
- package/src/docs/versioned/next/explanation/versioning-policy.md +3 -3
- package/src/docs/versioned/next/how-to/README.md +3 -2
- package/src/docs/versioned/next/how-to/add-feature-flags.md +50 -25
- package/src/docs/versioned/next/how-to/add-organizations.md +2 -1
- package/src/docs/versioned/next/how-to/admin-custom-home.md +8 -2
- package/src/docs/versioned/next/how-to/admin-custom-widget.md +0 -1
- package/src/docs/versioned/next/how-to/agent-ui-asks.md +6 -6
- package/src/docs/versioned/next/how-to/build-admin-screens.md +10 -8
- package/src/docs/versioned/next/how-to/build-for-web.md +1 -1
- package/src/docs/versioned/next/how-to/call-external-apis.md +2 -2
- package/src/docs/versioned/next/how-to/circleci.md +12 -6
- package/src/docs/versioned/next/how-to/configure-better-auth.md +114 -60
- package/src/docs/versioned/next/how-to/connect-mcp-service-token.md +10 -4
- package/src/docs/versioned/next/how-to/create-a-terreno-app.md +14 -2
- package/src/docs/versioned/next/how-to/debug-with-mcp.md +8 -13
- package/src/docs/versioned/next/how-to/expose-mcp-tools.md +15 -4
- package/src/docs/versioned/next/how-to/generate-the-client-sdk.md +33 -0
- package/src/docs/versioned/next/how-to/github-actions-ci.md +2 -2
- package/src/docs/versioned/next/how-to/in-app-notifications.md +1 -1
- package/src/docs/versioned/next/how-to/migrate-rtk-to-syncdb.md +318 -447
- package/src/docs/versioned/next/how-to/password-reset.md +1 -1
- package/src/docs/versioned/next/how-to/product-announcements.md +6 -3
- package/src/docs/versioned/next/how-to/rate-limiting.md +38 -16
- package/src/docs/versioned/next/how-to/run-mongodb-migrations.md +19 -0
- package/src/docs/versioned/next/how-to/run-tests-locally.md +2 -3
- package/src/docs/versioned/next/how-to/set-up-social-login.md +1 -1
- package/src/docs/versioned/next/how-to/set-up-terreno-mcp.md +2 -2
- package/src/docs/versioned/next/how-to/track-upstream-expo.md +1 -1
- package/src/docs/versioned/next/how-to/upgrade-banner.md +5 -3
- package/src/docs/versioned/next/how-to/upgrade-terreno.md +5 -5
- package/src/docs/versioned/next/how-to/use-syncdb-correctly.md +1 -1
- package/src/docs/versioned/next/how-to/websocket-integration.md +113 -402
- package/src/docs/versioned/next/implementationPlans/b2b-platform-program.md +1 -1
- package/src/docs/versioned/next/implementationPlans/migrate-admin-to-syncdb.md +5 -0
- package/src/docs/versioned/next/implementationPlans/native-module-baseline.md +29 -5
- package/src/docs/versioned/next/implementationPlans/remove-legacy-realtime.md +1 -1
- package/src/docs/versioned/next/implementationPlans/remove-rtk.md +185 -0
- package/src/docs/versioned/next/reference/README.md +1 -1
- package/src/docs/versioned/next/reference/admin-frontend.md +85 -70
- package/src/docs/versioned/next/reference/admin-spa.md +10 -4
- package/src/docs/versioned/next/reference/ai.md +36 -4
- package/src/docs/versioned/next/reference/announcements.md +3 -3
- package/src/docs/versioned/next/reference/api.md +39 -24
- package/src/docs/versioned/next/reference/cli.md +3 -4
- package/src/docs/versioned/next/reference/environment-variables.md +16 -16
- package/src/docs/versioned/next/reference/feature-flags.md +48 -7
- package/src/docs/versioned/next/reference/jobs.md +2 -2
- package/src/docs/versioned/next/reference/legacy/rtk.md +25 -600
- package/src/docs/versioned/next/reference/mcp-server.md +441 -1158
- package/src/docs/versioned/next/reference/syncdb.md +426 -16
- package/src/docs/versioned/next/reference/test.md +28 -3
- package/src/docs/versioned/next/reference/ui.md +132 -19
- package/src/docs/versioned/next/tasks/native-module-baseline.md +8 -4
- package/src/docs/versioned/next/tasks/rate-limiting.md +9 -2
- package/src/docs/versioned/next/tasks/remove-legacy-realtime.md +5 -5
- package/src/docs/versioned/next/tasks/remove-rtk.md +155 -0
- package/dist/docs/guidelines/rtk/guidelines/core.md +0 -26
- package/dist/docs/resources/rtk.md +0 -181
- package/dist/docs/templates/bootstrap/frontend/openapi-config.template.md +0 -16
- package/dist/docs/templates/bootstrap/frontend/scripts/generate-sdk.template.md +0 -49
- package/dist/docs/templates/bootstrap/frontend/store/appState.template.md +0 -45
- package/dist/docs/templates/bootstrap/frontend/store/errors.template.md +0 -51
- package/dist/docs/templates/bootstrap/frontend/store/index.template.md +0 -86
- package/dist/docs/templates/bootstrap/frontend/store/openApiSdk.template.md +0 -49
- package/dist/docs/templates/bootstrap/frontend/store/sdk.template.md +0 -80
- package/src/docs/guidelines/rtk/guidelines/core.md +0 -26
- package/src/docs/resources/rtk.md +0 -181
- package/src/docs/templates/bootstrap/frontend/openapi-config.template.md +0 -16
- package/src/docs/templates/bootstrap/frontend/scripts/generate-sdk.template.md +0 -49
- package/src/docs/templates/bootstrap/frontend/store/appState.template.md +0 -45
- package/src/docs/templates/bootstrap/frontend/store/errors.template.md +0 -51
- package/src/docs/templates/bootstrap/frontend/store/index.template.md +0 -86
- package/src/docs/templates/bootstrap/frontend/store/openApiSdk.template.md +0 -49
- package/src/docs/templates/bootstrap/frontend/store/sdk.template.md +0 -80
|
@@ -1,1354 +1,642 @@
|
|
|
1
1
|
# @terreno/mcp
|
|
2
2
|
|
|
3
|
-
Published npm package for the Terreno Model Context Protocol (MCP)
|
|
4
|
-
is `mcp-server/`. The package ships two servers with separate tool sets:
|
|
3
|
+
Published npm package for the Terreno Model Context Protocol (MCP) server. The monorepo directory is still `mcp-server/`. The package exposes:
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
| Hosted `terreno-mcp` | `terreno-mcp` → `dist/index.js` | `src/index.ts`, `src/httpApp.ts` | Streamable HTTP, stateless | 14 tools, 9 prompts, documentation resources |
|
|
9
|
-
| Local `terreno-mcp-local` | `terreno-mcp-local` → `dist/local/index.js` | `src/local/index.ts`, `src/local/localServer.ts` | stdio | 13 tools (no prompts, no resources) |
|
|
5
|
+
- **`terreno-mcp`** — HTTP server used in Cloud Run and local debugging (`src/index.ts`)
|
|
6
|
+
- **`terreno-mcp-local`** — stdio server for project runtime tools (`src/local/index.ts`): app/database/log/browser diagnostics and SyncDB state/action/snapshot tools (the Redux `get_rtk_state` tool was removed in Terreno 58). `evaluate`, `navigate`, and SyncDB state changes are gated by `TERRENO_MCP_EVAL`. Metro URL defaults from `frontend/package.json` `--port` or `TERRENO_METRO_URL`. `application_info` reads bootstrap `backend/` + `frontend/`, or this monorepo's `example-backend/` + `example-frontend/` (bootstrap names win when both exist).
|
|
10
7
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
It provides AI coding assistants with documentation access, code generation tools, and workflow prompts.
|
|
9
|
+
For editor configuration and runtime prerequisites, see
|
|
10
|
+
[Set up Terreno MCP](../how-to/set-up-terreno-mcp.md). For the end-to-end diagnostic workflow, see
|
|
11
|
+
[Debug a Terreno app with MCP](../how-to/debug-with-mcp.md).
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
the SDK's stateless legacy fallback for 2025-era clients. `terreno-mcp-local` uses v2 `serveStdio`
|
|
21
|
-
with `legacy: "serve"`, which negotiates the connection era and pins one server instance for that
|
|
13
|
+
Both HTTP MCP surfaces (`@terreno/mcp` and the `modelRouter` endpoint in
|
|
14
|
+
`@terreno/api`) use the MCP TypeScript SDK v2 and speak the stateless
|
|
15
|
+
`2026-07-28` protocol revision. The HTTP handlers retain the SDK's stateless
|
|
16
|
+
legacy fallback for 2025-era clients. `terreno-mcp-local` uses v2 `serveStdio`,
|
|
17
|
+
which negotiates the connection era and pins one server instance for that
|
|
22
18
|
connection.
|
|
23
19
|
|
|
24
20
|
## Table of Contents
|
|
25
21
|
|
|
26
|
-
- [
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
- [Local server (`terreno-mcp-local`)](#local-server-terreno-mcp-local)
|
|
33
|
-
- [Running the local server](#running-the-local-server)
|
|
34
|
-
- [Local tools](#local-tools)
|
|
35
|
-
- [`TERRENO_MCP_EVAL` gate](#terreno_mcp_eval-gate)
|
|
36
|
-
- [Metro and CDP connection](#metro-and-cdp-connection)
|
|
37
|
-
- [React Native DevTools and the `app` source](#react-native-devtools-and-the-app-source)
|
|
38
|
-
- [What the local server can and cannot see](#what-the-local-server-can-and-cannot-see)
|
|
39
|
-
- [Environment variables](#environment-variables)
|
|
22
|
+
- [Overview](#overview)
|
|
23
|
+
- [Installation](#installation)
|
|
24
|
+
- [Resources](#resources)
|
|
25
|
+
- [Tools](#tools)
|
|
26
|
+
- [Prompts](#prompts)
|
|
27
|
+
- [Environment Variables](#environment-variables)
|
|
40
28
|
- [Development](#development)
|
|
41
|
-
- [Architecture](#architecture)
|
|
42
|
-
- [Deployment](#deployment)
|
|
43
29
|
|
|
44
|
-
##
|
|
30
|
+
## Overview
|
|
31
|
+
|
|
32
|
+
The MCP server exposes Terreno's documentation and code generation capabilities through the Model Context Protocol, enabling AI assistants (like Claude in Cursor or Claude Desktop) to:
|
|
33
|
+
|
|
34
|
+
- Access up-to-date documentation for all Terreno packages
|
|
35
|
+
- Generate boilerplate code following Terreno conventions
|
|
36
|
+
- Provide multi-step workflows for common development tasks
|
|
37
|
+
|
|
38
|
+
**Key concepts:**
|
|
45
39
|
|
|
46
|
-
|
|
40
|
+
- **Resources**: Read-only documentation from `docs/` directory
|
|
41
|
+
- **Tools**: Code generators that return text (AI writes files), documentation search (`terreno_search_docs`, `terreno_get_component_docs`), upgrade notes (`terreno_get_upgrade_guide`), plus local-only tools when using `terreno-mcp-local`
|
|
42
|
+
- **Prompts**: Pre-built multi-step instructions for complex workflows
|
|
47
43
|
|
|
48
|
-
|
|
49
|
-
|------|-------|
|
|
50
|
-
| URL | `https://mcp.terreno.app/mcp` |
|
|
51
|
-
| JSON-RPC routes | `ALL /mcp` and `POST /` (same handler, same rate-limit bucket) |
|
|
52
|
-
| Health check | `GET /` → `{"mcpEndpoint":"/mcp","service":"terreno-mcp","status":"ok"}` (never rate limited) |
|
|
53
|
-
| Sessions | None. Each request is independent; no `initialize` round trip is required. |
|
|
54
|
-
| Request headers | `Accept: application/json, text/event-stream` is required; without both types the server returns JSON-RPC error `-32000` `Not Acceptable: Client must accept both application/json and text/event-stream` |
|
|
55
|
-
| Response | An SSE stream of `event: message` frames (`responseMode: "auto"`) |
|
|
56
|
-
| Logging | Every `tools/call` and `prompts/get` is logged with its name and arguments (`logger.info`), and the server is wrapped with `Sentry.wrapMcpServerWithSentry`. Do not put secrets or PHI in tool arguments. |
|
|
44
|
+
## Installation
|
|
57
45
|
|
|
58
|
-
|
|
59
|
-
`https://mcp.terreno.flourish.health/mcp` while `mcp.terreno.app` does not resolve
|
|
60
|
-
(`getaddrinfo ENOTFOUND mcp.terreno.app`).
|
|
46
|
+
### With Claude Desktop
|
|
61
47
|
|
|
62
|
-
|
|
63
|
-
`.mcp.json`; the full files are in [Set up Terreno MCP](../how-to/set-up-terreno-mcp.md)):
|
|
48
|
+
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
64
49
|
|
|
65
50
|
``````json
|
|
66
51
|
{
|
|
67
52
|
"mcpServers": {
|
|
68
|
-
"terreno": {
|
|
69
|
-
|
|
53
|
+
"terreno": {
|
|
54
|
+
"command": "bun",
|
|
55
|
+
"args": ["/absolute/path/to/terreno/mcp-server/dist/index.js"]
|
|
56
|
+
}
|
|
70
57
|
}
|
|
71
58
|
}
|
|
72
59
|
``````
|
|
73
60
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
``````bash
|
|
77
|
-
curl -s -X POST http://127.0.0.1:8799/mcp \
|
|
78
|
-
-H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' \
|
|
79
|
-
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"terreno_get_upgrade_guide","arguments":{"fromVersion":"57.14.0","toVersion":"57.14.0"}}}'
|
|
80
|
-
``````
|
|
81
|
-
|
|
82
|
-
``````text
|
|
83
|
-
event: message
|
|
84
|
-
data: {"result":{"content":[{"type":"text","text":"Recorded notes in 57.14.0 → 57.14.0: 57.14.0\n\n---\n\n# Upgrade to 57.14.0…"}]},"jsonrpc":"2.0","id":1}
|
|
85
|
-
``````
|
|
86
|
-
|
|
87
|
-
JSON-RPC methods: `tools/list`, `tools/call`, `prompts/list`, `prompts/get`, `resources/list`,
|
|
88
|
-
`resources/read`.
|
|
89
|
-
|
|
90
|
-
### Hosted tools
|
|
91
|
-
|
|
92
|
-
Code generators return text. They do not write files: the agent receives the code and a target path
|
|
93
|
-
and writes it. Scaffold a new app with [`create-terreno-app`](create-terreno-app.md)
|
|
94
|
-
(`bunx create-terreno-app`), not an MCP tool. Every tool returns one text content block.
|
|
95
|
-
|
|
96
|
-
| Tool | Purpose |
|
|
97
|
-
|------|---------|
|
|
98
|
-
| [`terreno_bootstrap_ai_rules`](#terreno_bootstrap_ai_rules) | Generate AI assistant rule files for an app |
|
|
99
|
-
| [`terreno_search_docs`](#terreno_search_docs) | Keyword search over bundled Terreno docs |
|
|
100
|
-
| [`terreno_get_component_docs`](#terreno_get_component_docs) | Props table for one `@terreno/ui` component |
|
|
101
|
-
| [`terreno_get_upgrade_guide`](#terreno_get_upgrade_guide) | Bundled upgrade notes between two versions |
|
|
102
|
-
| [`terreno_search_update_notes`](#terreno_search_update_notes) | Search upgrade notes and help-API announcements |
|
|
103
|
-
| [`terreno_get_update_note`](#terreno_get_update_note) | Full text of one update note |
|
|
104
|
-
| [`terreno_ask_update_help`](#terreno_ask_update_help) | Ranked update-note excerpts for a question |
|
|
105
|
-
| [`terreno_generate_model`](#terreno_generate_model) | Mongoose model source |
|
|
106
|
-
| [`terreno_generate_route`](#terreno_generate_route) | `modelRouter` route source |
|
|
107
|
-
| [`terreno_generate_screen`](#terreno_generate_screen) | React Native screen source |
|
|
108
|
-
| [`terreno_generate_form_fields`](#terreno_generate_form_fields) | `@terreno/ui` form field source |
|
|
109
|
-
| [`terreno_validate_model_schema`](#terreno_validate_model_schema) | Check schema source against Terreno conventions |
|
|
110
|
-
| [`terreno_validate_ui_blocks`](#terreno_validate_ui_blocks) | Validate a whole-reply UI block document |
|
|
111
|
-
| [`terreno_install_admin`](#terreno_install_admin) | Admin panel files and setup steps |
|
|
112
|
-
|
|
113
|
-
Example outputs below are real tool output, shortened with `…`.
|
|
114
|
-
|
|
115
|
-
#### terreno_bootstrap_ai_rules
|
|
116
|
-
|
|
117
|
-
Generate AI coding assistant rules (`AGENTS.md`, `CLAUDE.md`, `.rulesync/` sources, and
|
|
118
|
-
`rulesync.jsonc`). Guideline bodies come from each package's `.ai/guidelines/core.md`, copied into
|
|
119
|
-
this package at build time (`bun run sync-package-guidelines`). Defined in `src/bootstrap.ts`.
|
|
120
|
-
|
|
121
|
-
| Parameter | Type | Required | Description |
|
|
122
|
-
|-----------|------|----------|-------------|
|
|
123
|
-
| `appName` | string | yes | App name in kebab-case |
|
|
124
|
-
| `appDisplayName` | string | yes | Human-readable name |
|
|
125
|
-
| `description` | string | no | One-line app description |
|
|
126
|
-
| `packages` | string[] | no | Guideline packages to merge: `api`, `ui`, `rtk`, `syncdb`, `admin-backend`, `admin-frontend`, or the `@terreno/*` name. Omitted or no valid id means all six. |
|
|
127
|
-
|
|
128
|
-
``````json
|
|
129
|
-
{"name":"terreno_bootstrap_ai_rules","arguments":{"appName":"my-app","appDisplayName":"My App","packages":["api"]}}
|
|
130
|
-
``````
|
|
131
|
-
|
|
132
|
-
``````markdown
|
|
133
|
-
# Bootstrap AI Rules for My App
|
|
134
|
-
|
|
135
|
-
## Files to Create
|
|
136
|
-
|
|
137
|
-
The following AI coding assistant configuration files need to be created:
|
|
138
|
-
|
|
139
|
-
- `.rulesync/rules/00-root.md`
|
|
140
|
-
- `backend/AGENTS.md`
|
|
141
|
-
- `backend/CLAUDE.md`
|
|
142
|
-
- `frontend/AGENTS.md`
|
|
143
|
-
- `frontend/CLAUDE.md`
|
|
144
|
-
- `rulesync.jsonc`
|
|
145
|
-
|
|
146
|
-
## Instructions
|
|
147
|
-
|
|
148
|
-
1. **Create all the files listed above.** Each file's content is provided below.
|
|
149
|
-
…
|
|
150
|
-
3. **Before generating, move hand-written rules into `.rulesync/rules/`.** `rulesync generate` overwrites the root `CLAUDE.md`, `AGENTS.md`, and `.github/copilot-instructions.md` and deletes every file under `.claude/rules/`, `.cursor/rules/`, `.github/instructions/`, and `.agents/memories/` that it did not generate. …
|
|
151
|
-
|
|
152
|
-
4. **Delete the stale `.cursorrules`** that `create-terreno-app` wrote. …
|
|
153
|
-
|
|
154
|
-
5. **Generate the editor files with rulesync:**
|
|
155
|
-
```bash
|
|
156
|
-
bunx rulesync@9 generate
|
|
157
|
-
```
|
|
158
|
-
…
|
|
159
|
-
``````
|
|
160
|
-
|
|
161
|
-
`rulesync.jsonc` targets `cursor`, `claudecode`, `copilot`, and `agentsmd`. The one
|
|
162
|
-
`root: true` rule in `00-root.md` covers all four. See
|
|
163
|
-
[Agent guidelines](../explanation/agent-guidelines.md#terreno_bootstrap_ai_rules) for the
|
|
164
|
-
generated editor files and how to add project rules.
|
|
165
|
-
|
|
166
|
-
#### terreno_search_docs
|
|
167
|
-
|
|
168
|
-
BM25-style keyword search over markdown bundled with the server: `docs/resources/*.md`, the Diátaxis
|
|
169
|
-
docs synced into `docs/versioned/`, and per-component excerpts from `ui-types-documentation.json`.
|
|
170
|
-
Call it before guessing a Terreno API.
|
|
171
|
-
|
|
172
|
-
| Parameter | Type | Required | Description |
|
|
173
|
-
|-----------|------|----------|-------------|
|
|
174
|
-
| `queries` | string[] | yes | One or more search phrases |
|
|
175
|
-
| `packages` | string[] | no | Filter by package id or scope, e.g. `["api", "@terreno/ui"]` |
|
|
176
|
-
| `tokenLimit` | number | no | Approximate markdown budget. Default 3000, clamped to 8000. |
|
|
177
|
-
| `version` | string | no | `@terreno/*` lockstep version (e.g. `57.2.0`). Omit for current `next` docs. |
|
|
61
|
+
### With Claude Code CLI
|
|
178
62
|
|
|
179
|
-
|
|
180
|
-
copied into `docs/versioned/` at build), and the response says so. Range prefixes such as
|
|
181
|
-
`^57.2.0` are stripped. A non-array `queries` returns a usage message instead of results.
|
|
63
|
+
Add to your project's `.claude/settings.json`:
|
|
182
64
|
|
|
183
65
|
``````json
|
|
184
|
-
{
|
|
66
|
+
{
|
|
67
|
+
"mcpServers": {
|
|
68
|
+
"terreno": {
|
|
69
|
+
"command": "bun",
|
|
70
|
+
"args": ["./mcp-server/dist/index.js"]
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
185
74
|
``````
|
|
186
75
|
|
|
187
|
-
|
|
188
|
-
# Terreno documentation search results
|
|
76
|
+
### Building from Source
|
|
189
77
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
78
|
+
``````bash
|
|
79
|
+
# From monorepo root
|
|
80
|
+
bun install
|
|
81
|
+
bun run mcp:build
|
|
193
82
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
_…Truncated to approximate token budget (~300 tokens)._
|
|
83
|
+
# Or from mcp-server directory
|
|
84
|
+
cd mcp-server
|
|
85
|
+
bun run build
|
|
198
86
|
``````
|
|
199
87
|
|
|
200
|
-
|
|
88
|
+
## Resources
|
|
201
89
|
|
|
202
|
-
|
|
203
|
-
related markdown excerpts.
|
|
90
|
+
Documentation resources accessible via `terreno://` protocol:
|
|
204
91
|
|
|
205
|
-
|
|
|
206
|
-
|
|
207
|
-
| `
|
|
208
|
-
| `
|
|
92
|
+
| URI | Description |
|
|
93
|
+
|-----|-------------|
|
|
94
|
+
| `terreno://docs/overview` | Monorepo overview and architecture |
|
|
95
|
+
| `terreno://docs/api` | @terreno/api reference documentation |
|
|
96
|
+
| `terreno://docs/ui` | @terreno/ui reference documentation |
|
|
97
|
+
| `terreno://docs/syncdb` | @terreno/syncdb: synced collections, request client + generated API hooks, auth session, config, flags |
|
|
98
|
+
| `terreno://docs/patterns` | Common patterns and best practices |
|
|
209
99
|
|
|
210
|
-
|
|
211
|
-
{"name":"terreno_get_component_docs","arguments":{"component":"Badge"}}
|
|
212
|
-
``````
|
|
100
|
+
**How it works:**
|
|
213
101
|
|
|
214
|
-
|
|
215
|
-
|
|
102
|
+
- Resources are loaded from markdown files in `docs/` directory
|
|
103
|
+
- Content is transformed and served via MCP protocol
|
|
104
|
+
- AI assistants cache resources for fast lookup
|
|
105
|
+
- Updates require MCP server restart
|
|
216
106
|
|
|
217
|
-
**
|
|
107
|
+
**Custom docs directory:**
|
|
218
108
|
|
|
219
|
-
|
|
109
|
+
Set `TERRENO_MCP_DOCS_DIR` environment variable to override default path.
|
|
220
110
|
|
|
221
|
-
|
|
222
|
-
|------|------|----------|-------------|
|
|
223
|
-
| `color` | `"bold" | "subtle"` | No | For the "status" variant, whether the dot uses the bold (saturated) or …
|
|
224
|
-
…
|
|
225
|
-
``````
|
|
111
|
+
## Tools
|
|
226
112
|
|
|
227
|
-
|
|
228
|
-
|
|
113
|
+
Code generation tools return TypeScript/JavaScript code as text. **Code generation tools do not
|
|
114
|
+
write files** — the AI assistant receives the code and writes it to appropriate locations. Scaffold
|
|
115
|
+
a new app with [`create-terreno-app`](create-terreno-app.md) (`bunx create-terreno-app`), not an MCP
|
|
116
|
+
tool.
|
|
229
117
|
|
|
230
|
-
|
|
118
|
+
The local `browser` tool is different: its `screenshot` action writes the requested image path so an
|
|
119
|
+
agent can attach the rendered result as verification evidence. It keeps one headless session alive
|
|
120
|
+
for the MCP connection. Call `open` first, perform interactions, call `snapshot` and `screenshot` to
|
|
121
|
+
prove the final state, then call `close`.
|
|
231
122
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
changed". Note format: `mcp-server/src/docs/upgrades/README.md`.
|
|
235
|
-
|
|
236
|
-
| Parameter | Type | Required | Description |
|
|
237
|
-
|-----------|------|----------|-------------|
|
|
238
|
-
| `fromVersion` | string | yes | Installed `@terreno/*` semver. Must be ≤ `toVersion`. |
|
|
239
|
-
| `toVersion` | string | yes | Target semver |
|
|
123
|
+
`open` accepts only `http:` and `https:` URLs. Snapshots redact password input values; use them for
|
|
124
|
+
page structure and visible state, not credential inspection.
|
|
240
125
|
|
|
241
126
|
``````json
|
|
242
|
-
{"name":"
|
|
127
|
+
{"name":"browser","arguments":{"action":"open","url":"http://localhost:8082","width":1280,"height":720}}
|
|
128
|
+
{"name":"browser","arguments":{"action":"wait","timeout":1000}}
|
|
129
|
+
{"name":"browser","arguments":{"action":"click","selector":"button[type=submit]"}}
|
|
130
|
+
{"name":"browser","arguments":{"action":"snapshot"}}
|
|
131
|
+
{"name":"browser","arguments":{"action":"screenshot","output":"/opt/cursor/artifacts/app.png"}}
|
|
132
|
+
{"name":"browser","arguments":{"action":"close"}}
|
|
243
133
|
``````
|
|
244
134
|
|
|
245
|
-
|
|
246
|
-
|
|
135
|
+
`browser` requires Bun 1.4 or newer. macOS uses system WebKit; Linux and Windows use an installed
|
|
136
|
+
Chrome, Chromium, or Edge through the Chrome DevTools Protocol. Browser storage is ephemeral unless
|
|
137
|
+
`open` receives `dataDir`. Set `TERRENO_MCP_EVAL=1` to enable its arbitrary-JavaScript `evaluate`
|
|
138
|
+
action. Screenshot paths must stay under the project root or `/opt/cursor/artifacts`; persistent
|
|
139
|
+
browser data must stay under the project root. Calls are serialized around the one session owned by
|
|
140
|
+
the local MCP process.
|
|
247
141
|
|
|
248
|
-
|
|
142
|
+
### SyncDB runtime tools
|
|
249
143
|
|
|
250
|
-
|
|
144
|
+
Create the app client with `debug: true` so it registers by its configured
|
|
145
|
+
`name`. The local MCP uses the in-process registry when available and Hermes CDP
|
|
146
|
+
for a separately running app.
|
|
251
147
|
|
|
252
|
-
|
|
148
|
+
| Tool | Purpose |
|
|
149
|
+
| --- | --- |
|
|
150
|
+
| `get_syncdb_state` | Read status, entities/tombstones, outbox, conflicts, cursors, streams, repair markers, values, and debugger events |
|
|
151
|
+
| `syncdb_snapshot` | Capture, list, get, compare, or delete snapshots held by this MCP process |
|
|
152
|
+
| `syncdb_action` | Mutate or directly edit local state, flush, reconcile/resync, resolve/retry, toggle offline, clear debug events, or merge a snapshot |
|
|
253
153
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
154
|
+
State and snapshot responses redact fields containing `password`, `token`,
|
|
155
|
+
`secret`, `authorization`, or `cookie`. Snapshot merge payloads are retained
|
|
156
|
+
privately and are not returned. Start the local MCP with
|
|
157
|
+
`TERRENO_MCP_EVAL=1` before calling `syncdb_action`.
|
|
258
158
|
|
|
259
|
-
|
|
159
|
+
See [Debug a Terreno app with MCP](../how-to/debug-with-mcp.md) for examples and
|
|
160
|
+
safety guidance.
|
|
260
161
|
|
|
261
|
-
|
|
262
|
-
Terreno backend help API. Returns JSON.
|
|
162
|
+
### terreno_search_docs
|
|
263
163
|
|
|
264
|
-
|
|
265
|
-
|-----------|------|----------|-------------|
|
|
266
|
-
| `queries` | string[] | no | Keyword phrases |
|
|
267
|
-
| `question` | string | no | Natural-language question, used as an extra phrase |
|
|
268
|
-
| `source` | `auto` \| `bundled` \| `announcement` | no | Default `auto` |
|
|
269
|
-
| `limit` | number | no | Default 10 |
|
|
270
|
-
| `includeArchived` | boolean | no | Include archived announcements |
|
|
164
|
+
BM25-style keyword search over markdown bundled with the MCP server: `docs/resources/*.md`, synced Diátaxis docs under `docs/versioned/`, and per-component excerpts derived from `ui-types-documentation.json`. **Prefer this tool before guessing** Terreno APIs (same posture as Laravel Boost `search-docs`).
|
|
271
165
|
|
|
272
|
-
|
|
273
|
-
{"name":"terreno_search_update_notes","arguments":{"queries":["rate limit"],"limit":2}}
|
|
274
|
-
``````
|
|
166
|
+
**Parameters:**
|
|
275
167
|
|
|
276
|
-
``````
|
|
168
|
+
``````typescript
|
|
277
169
|
{
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
"kind": "upgrade",
|
|
283
|
-
"title": "Terreno 57.3.0 upgrade notes",
|
|
284
|
-
"version": "57.3.0"
|
|
285
|
-
},
|
|
286
|
-
…
|
|
287
|
-
],
|
|
288
|
-
"sources": [
|
|
289
|
-
"bundled-upgrades"
|
|
290
|
-
]
|
|
170
|
+
queries: string[]; // Required — one or more search phrases
|
|
171
|
+
packages?: string[]; // Optional — filter by package id or scope, e.g. ["api", "@terreno/ui"]
|
|
172
|
+
tokenLimit?: number; // Approximate max tokens of markdown (default 3000)
|
|
173
|
+
version?: string; // Optional @terreno/* lockstep version (e.g. 57.2.0). Omit for current `next` docs.
|
|
291
174
|
}
|
|
292
175
|
``````
|
|
293
176
|
|
|
294
|
-
|
|
177
|
+
Unmatched versions fall back to the nearest retained snapshot (`website/versioned_docs/`, copied into `docs/versioned/` at MCP build). The response names the resolved version and includes a note when a fallback happened. Pass the consumer app's `@terreno/*` version from `application_info` or `package.json`. Range prefixes such as `^57.2.0` are stripped before matching.
|
|
295
178
|
|
|
296
|
-
|
|
179
|
+
### terreno_get_component_docs
|
|
297
180
|
|
|
298
|
-
|
|
299
|
-
|-----------|------|----------|-------------|
|
|
300
|
-
| `id` | string | yes | `upgrade:<semver>`, `announcement:<mongoId>`, or a bare upgrade semver |
|
|
301
|
-
| `includeArchived` | boolean | no | Allow archived announcements from the help API |
|
|
181
|
+
Returns the full props table for a single `@terreno/ui` component from `ui-types-documentation.json`, plus short related markdown excerpts when the search index finds matches.
|
|
302
182
|
|
|
303
|
-
|
|
304
|
-
{"name":"terreno_get_update_note","arguments":{"id":"upgrade:57.14.0"}}
|
|
305
|
-
``````
|
|
183
|
+
**Parameters:**
|
|
306
184
|
|
|
307
|
-
``````
|
|
185
|
+
``````typescript
|
|
308
186
|
{
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
"kind": "upgrade",
|
|
312
|
-
"title": "Terreno 57.14.0 upgrade notes",
|
|
313
|
-
"version": "57.14.0"
|
|
187
|
+
component: string; // e.g. "Button", "TextField"
|
|
188
|
+
version?: string; // Optional @terreno/* lockstep version. Omit for current TypeDoc props.
|
|
314
189
|
}
|
|
315
190
|
``````
|
|
316
191
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
Answer a question with ranked update-note excerpts and the ids to fetch with
|
|
320
|
-
`terreno_get_update_note`. Returns text.
|
|
321
|
-
|
|
322
|
-
| Parameter | Type | Required | Description |
|
|
323
|
-
|-----------|------|----------|-------------|
|
|
324
|
-
| `question` | string | yes | Question about what changed |
|
|
325
|
-
| `limit` | number | no | Default 5 |
|
|
326
|
-
| `includeArchived` | boolean | no | Include archived announcements |
|
|
327
|
-
|
|
328
|
-
``````json
|
|
329
|
-
{"name":"terreno_ask_update_help","arguments":{"question":"How do I enable rate limiting?","limit":2}}
|
|
330
|
-
``````
|
|
331
|
-
|
|
332
|
-
``````text
|
|
333
|
-
Question: How do I enable rate limiting?
|
|
334
|
-
Sources: bundled-upgrades
|
|
192
|
+
When `version` matches a retained docs snapshot, the tool returns that version's generated component page (MDX chrome stripped). Snapshot filenames may be hyphenated (`text-field.mdx`) or concatenated (`userinactivity.mdx`); lookup tries both. Otherwise it uses current `ui-types-documentation.json` and notes the fallback.
|
|
335
193
|
|
|
336
|
-
|
|
337
|
-
- [upgrade] Terreno 57.3.0 upgrade notes (upgrade:57.3.0)
|
|
338
|
-
# Upgrading to 57.3.0 **Action required:** Yes …
|
|
339
|
-
- [upgrade] Terreno 58.0.0 upgrade notes (upgrade:58.0.0)
|
|
340
|
-
…
|
|
341
|
-
``````
|
|
342
|
-
|
|
343
|
-
#### terreno_generate_model
|
|
194
|
+
### terreno_get_upgrade_guide
|
|
344
195
|
|
|
345
|
-
|
|
346
|
-
`addDefaultPlugins`. Target path: `backend/src/models/<name>.ts`.
|
|
196
|
+
Return bundled Terreno lockstep upgrade notes between two semver versions (markdown). Use before major bumps to `@terreno/*` packages. The response always lists which versions in the range **have** notes. If some or all versions have none, it names those gaps — an empty concatenation would look like “nothing changed,” which is usually false. `fromVersion` must be less than or equal to `toVersion`. Note format: `mcp-server/src/docs/upgrades/README.md`.
|
|
347
197
|
|
|
348
|
-
|
|
349
|
-
|-----------|------|----------|-------------|
|
|
350
|
-
| `name` | string | yes | Model name, PascalCase |
|
|
351
|
-
| `fields` | object[] | yes | Each `{name*, type*, required?, unique?, ref?, default?}`. `type`: `String`, `Number`, `Boolean`, `Date`, `ObjectId`, `Array`, `Mixed`. `default` is a string. |
|
|
352
|
-
| `hasOwner` | boolean | no | Add a required `ownerId` referencing `User` |
|
|
353
|
-
| `softDelete` | boolean | no | Enable soft delete |
|
|
198
|
+
**Parameters:**
|
|
354
199
|
|
|
355
|
-
``````
|
|
356
|
-
{
|
|
200
|
+
``````typescript
|
|
201
|
+
{
|
|
202
|
+
fromVersion: string; // Installed @terreno/* semver (e.g. 0.19.0)
|
|
203
|
+
toVersion: string; // Target semver to upgrade to (e.g. 0.20.0)
|
|
204
|
+
}
|
|
357
205
|
``````
|
|
358
206
|
|
|
359
|
-
|
|
360
|
-
**IMPORTANT: Write this code to a file**
|
|
361
|
-
|
|
362
|
-
File path: `backend/src/models/product.ts`
|
|
207
|
+
### terreno_generate_model
|
|
363
208
|
|
|
364
|
-
|
|
365
|
-
1. Export from `backend/src/models/index.ts`: `export * from "./product";`
|
|
209
|
+
Generate a Mongoose model with Terreno conventions (timestamps, soft delete, owner tracking, type definitions).
|
|
366
210
|
|
|
367
|
-
|
|
211
|
+
**Parameters:**
|
|
368
212
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
213
|
+
``````typescript
|
|
214
|
+
{
|
|
215
|
+
name: string; // Model name (PascalCase)
|
|
216
|
+
fields: Array<{
|
|
217
|
+
name: string; // Field name (camelCase)
|
|
218
|
+
type: string; // "String" | "Number" | "Boolean" | "Date" | "ObjectId"
|
|
219
|
+
required?: boolean;
|
|
220
|
+
default?: string; // Default value as string
|
|
221
|
+
ref?: string; // Referenced model name (for ObjectId)
|
|
222
|
+
description?: string; // Field description (recommended)
|
|
223
|
+
}>;
|
|
224
|
+
hasOwner?: boolean; // Add ownerId field (default: false)
|
|
225
|
+
softDelete?: boolean; // Add deleted field (default: false)
|
|
226
|
+
timestamps?: boolean; // Add created/updated fields (default: true)
|
|
227
|
+
}
|
|
378
228
|
``````
|
|
379
229
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
Generate a `modelRouter` route. Target path: `backend/src/api/<model>.ts`.
|
|
383
|
-
|
|
384
|
-
| Parameter | Type | Required | Description |
|
|
385
|
-
|-----------|------|----------|-------------|
|
|
386
|
-
| `modelName` | string | yes | Model name, PascalCase |
|
|
387
|
-
| `routePath` | string | yes | API path, e.g. `/products` |
|
|
388
|
-
| `permissions` | object | no | `{create, list, read, update, delete}`, each `admin`, `any`, `authenticated`, `authOrReadOnly`, or `owner`. A missing or unknown value becomes `Permissions.IsAuthenticated`. |
|
|
389
|
-
| `queryFields` | string[] | no | Allowed query fields |
|
|
390
|
-
| `sort` | string | no | Default sort, e.g. `-created` |
|
|
391
|
-
| `ownerFiltered` | boolean | no | Add `OwnerQueryFilter` and an `ownerId`-setting `preCreate` |
|
|
230
|
+
**Example:**
|
|
392
231
|
|
|
393
232
|
``````json
|
|
394
|
-
{
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
2. Register in server setup: `addProductRoutes(router, options);`
|
|
405
|
-
3. Regenerate frontend SDK: `bun run sdk` in the frontend directory
|
|
406
|
-
…
|
|
233
|
+
{
|
|
234
|
+
"name": "Product",
|
|
235
|
+
"fields": [
|
|
236
|
+
{"name": "title", "type": "String", "required": true, "description": "Product title"},
|
|
237
|
+
{"name": "price", "type": "Number", "required": true, "description": "Price in cents"},
|
|
238
|
+
{"name": "active", "type": "Boolean", "default": "true", "description": "Is product active"}
|
|
239
|
+
],
|
|
240
|
+
"hasOwner": true,
|
|
241
|
+
"softDelete": true
|
|
242
|
+
}
|
|
407
243
|
``````
|
|
408
244
|
|
|
409
|
-
|
|
245
|
+
**Returns:**
|
|
410
246
|
|
|
411
|
-
|
|
412
|
-
|
|
247
|
+
- Model schema code with proper type definitions
|
|
248
|
+
- Methods and statics structure
|
|
249
|
+
- Plugin configuration
|
|
250
|
+
- Export statements
|
|
413
251
|
|
|
414
|
-
|
|
415
|
-
|-----------|------|----------|-------------|
|
|
416
|
-
| `name` | string | yes | Screen name, PascalCase |
|
|
417
|
-
| `type` | `list` \| `detail` \| `form` \| `empty` | yes | Screen kind |
|
|
418
|
-
| `modelName` | string | no | Model for data fetching |
|
|
419
|
-
| `fields` | string[] | no | Fields to display or edit |
|
|
252
|
+
### terreno_generate_route
|
|
420
253
|
|
|
421
|
-
|
|
422
|
-
{"name":"terreno_generate_screen","arguments":{"name":"ProductList","type":"list","modelName":"Product","fields":["title"]}}
|
|
423
|
-
``````
|
|
254
|
+
Generate modelRouter configuration with permissions and query options.
|
|
424
255
|
|
|
425
|
-
|
|
426
|
-
**IMPORTANT: Write this code to a file**
|
|
256
|
+
**Parameters:**
|
|
427
257
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
258
|
+
``````typescript
|
|
259
|
+
{
|
|
260
|
+
modelName: string; // Model name (PascalCase)
|
|
261
|
+
routePath: string; // API path (e.g., "/products")
|
|
262
|
+
permissions?: {
|
|
263
|
+
create?: "any" | "authenticated" | "admin" | "owner";
|
|
264
|
+
list?: "any" | "authenticated" | "admin" | "owner";
|
|
265
|
+
read?: "any" | "authenticated" | "admin" | "owner";
|
|
266
|
+
update?: "any" | "authenticated" | "admin" | "owner";
|
|
267
|
+
delete?: "any" | "authenticated" | "admin" | "owner";
|
|
268
|
+
};
|
|
269
|
+
queryFields?: string[]; // Allowed query parameters
|
|
270
|
+
ownerFiltered?: boolean; // Apply OwnerQueryFilter (default: false)
|
|
271
|
+
sort?: string; // Default sort order (e.g., "-created")
|
|
272
|
+
populate?: Array<{path: string; fields?: string[]}>;
|
|
273
|
+
}
|
|
435
274
|
``````
|
|
436
275
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
Generate `@terreno/ui` form fields and their state declarations. Fields use the real
|
|
440
|
-
`@terreno/ui` props (`title`, `value`, `onChange`, `errorText`); `password` renders
|
|
441
|
-
`TextField type="password"`, and `number` and date values are strings. A required field adds an
|
|
442
|
-
`errors` state and `errorText={errors.<name>}`.
|
|
443
|
-
|
|
444
|
-
| Parameter | Type | Required | Description |
|
|
445
|
-
|-----------|------|----------|-------------|
|
|
446
|
-
| `fields` | object[] | yes | Each `{name*, type*, label?, required?, options?}`. `type`: `text`, `email`, `password`, `number`, `textarea`, `select`, `boolean`, `date`, `datetime`. `options` is `[{label, value}]` for `select`. |
|
|
276
|
+
**Example:**
|
|
447
277
|
|
|
448
278
|
``````json
|
|
449
|
-
{
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
…
|
|
279
|
+
{
|
|
280
|
+
"modelName": "Product",
|
|
281
|
+
"routePath": "/products",
|
|
282
|
+
"permissions": {
|
|
283
|
+
"create": "authenticated",
|
|
284
|
+
"list": "any",
|
|
285
|
+
"read": "any",
|
|
286
|
+
"update": "owner",
|
|
287
|
+
"delete": "admin"
|
|
288
|
+
},
|
|
289
|
+
"queryFields": ["active", "category"],
|
|
290
|
+
"ownerFiltered": true,
|
|
291
|
+
"sort": "-created"
|
|
292
|
+
}
|
|
464
293
|
``````
|
|
465
294
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
Check schema source text against Terreno conventions and list issues and suggestions. The
|
|
469
|
-
model's `<Name>Document` type may be declared in the file or imported from the app's type files
|
|
470
|
-
(`src/modelInterfaces.ts`, `src/types/models/`); "Missing TypeScript interfaces" means neither.
|
|
295
|
+
**Returns:**
|
|
471
296
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
297
|
+
- Router setup code with modelRouter configuration
|
|
298
|
+
- Permission mapping
|
|
299
|
+
- Lifecycle hooks structure
|
|
300
|
+
- Instructions for registering route
|
|
475
301
|
|
|
476
|
-
|
|
477
|
-
{"name":"terreno_validate_model_schema","arguments":{"schema":"const s = new mongoose.Schema({title: {type: String}});"}}
|
|
478
|
-
``````
|
|
302
|
+
### terreno_generate_screen
|
|
479
303
|
|
|
480
|
-
|
|
481
|
-
Schema Validation Results:
|
|
304
|
+
Generate React Native screen component with Terreno UI components.
|
|
482
305
|
|
|
483
|
-
|
|
484
|
-
- Missing strict: 'throw' in schema options
|
|
485
|
-
- Missing toJSON virtuals configuration
|
|
486
|
-
- Missing default plugins
|
|
487
|
-
- Missing TypeScript interfaces
|
|
306
|
+
**Parameters:**
|
|
488
307
|
|
|
489
|
-
|
|
490
|
-
|
|
308
|
+
``````typescript
|
|
309
|
+
{
|
|
310
|
+
name: string; // Screen name (PascalCase)
|
|
311
|
+
type: "list" | "detail" | "form" | "empty";
|
|
312
|
+
modelName?: string; // Model name for CRUD screens
|
|
313
|
+
fields?: string[]; // Fields to display/edit
|
|
314
|
+
collection?: string; // Synced collection (default: kebab-case plural of modelName)
|
|
315
|
+
}
|
|
491
316
|
``````
|
|
492
317
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
Validate one whole-reply YAML or JSON block document. The text is the report
|
|
496
|
-
`terreno-blocks validate` prints: one line per problem, `path CODE message — fix`. A valid document
|
|
497
|
-
with no warnings returns an empty string.
|
|
498
|
-
|
|
499
|
-
| Parameter | Type | Required | Description |
|
|
500
|
-
|-----------|------|----------|-------------|
|
|
501
|
-
| `document` | string | yes | The YAML or JSON document |
|
|
318
|
+
**Example:**
|
|
502
319
|
|
|
503
320
|
``````json
|
|
504
|
-
{
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
#### terreno_install_admin
|
|
512
|
-
|
|
513
|
-
Generate admin panel screen files and backend/frontend setup steps for `@terreno/admin-backend` and
|
|
514
|
-
`@terreno/admin-frontend`.
|
|
515
|
-
|
|
516
|
-
| Parameter | Type | Required | Description |
|
|
517
|
-
|-----------|------|----------|-------------|
|
|
518
|
-
| `models` | object[] | yes | Each `{modelName*, routePath*, displayName*, listFields*}`; `listFields` is string[] |
|
|
519
|
-
|
|
520
|
-
``````json
|
|
521
|
-
{"name":"terreno_install_admin","arguments":{"models":[{"modelName":"Todo","routePath":"/todos","displayName":"Todos","listFields":["title"]}]}}
|
|
321
|
+
{
|
|
322
|
+
"name": "ProductList",
|
|
323
|
+
"type": "list",
|
|
324
|
+
"modelName": "Product",
|
|
325
|
+
"fields": ["title", "price", "active"]
|
|
326
|
+
}
|
|
522
327
|
``````
|
|
523
328
|
|
|
524
|
-
|
|
525
|
-
# Install Admin Panel
|
|
329
|
+
**Returns:**
|
|
526
330
|
|
|
527
|
-
|
|
331
|
+
- React Native functional component
|
|
332
|
+
- `@terreno/syncdb/react` hooks against the synced collection: `useQuery` + `useSyncStatus` (list), `useEntity` (detail), `useMutate().create` (form). For a model that is not synced, swap them for the generated `@/store/apiSdk` hooks
|
|
333
|
+
- @terreno/ui components (Box, Text, Button, Page, etc.)
|
|
334
|
+
- Empty and not-found states
|
|
528
335
|
|
|
529
|
-
|
|
530
|
-
- `frontend/app/(tabs)/admin/[model].tsx`
|
|
531
|
-
- `frontend/app/(tabs)/admin/[model]/create.tsx`
|
|
532
|
-
- `frontend/app/(tabs)/admin/[model]/[id].tsx`
|
|
336
|
+
### terreno_generate_form_fields
|
|
533
337
|
|
|
534
|
-
|
|
338
|
+
Generate form field components for a model.
|
|
535
339
|
|
|
536
|
-
|
|
537
|
-
…
|
|
538
|
-
``````
|
|
340
|
+
**Parameters:**
|
|
539
341
|
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
Multi-step workflow prompts, served by `prompts/list` and `prompts/get`. `terreno_bootstrap` is
|
|
543
|
-
defined in `src/bootstrap.ts`; the rest in `src/prompts.ts`. `*` marks a required argument. All
|
|
544
|
-
arguments are strings.
|
|
545
|
-
|
|
546
|
-
| Prompt | Arguments | Purpose |
|
|
547
|
-
|--------|-----------|---------|
|
|
548
|
-
| `terreno_bootstrap` | `appName*`, `appDisplayName*` | Run `bunx create-terreno-app`, then `terreno_bootstrap_ai_rules` |
|
|
549
|
-
| `terreno_create_crud_feature` | `name*`, `fields*` (`title:string,price:number`), `hasOwner` (`yes`/`no`) | Model, routes, and frontend screens |
|
|
550
|
-
| `terreno_create_api_endpoint` | `path*`, `method*`, `description*` | Custom endpoint with OpenAPI docs |
|
|
551
|
-
| `terreno_create_ui_component` | `name*`, `type*` (`display`, `interactive`, `form`, `layout`) | Reusable `@terreno/ui`-style component |
|
|
552
|
-
| `terreno_create_form_screen` | `name*`, `fields*` (`name:text,email:email`), `endpoint*` | Form screen with validation |
|
|
553
|
-
| `terreno_add_authentication` | `features` (`email,social,passwordReset`) | Login/signup screens and auth state |
|
|
554
|
-
| `terreno_style_guide` | none | Terreno code style guide |
|
|
555
|
-
| `terreno_migrate_to_terreno_app` | `serverFile` | Move from `setupServer` to `TerrenoApp` |
|
|
556
|
-
| `terreno_upgrade` | `targetVersion` (omit for latest stable) | Lockstep upgrade: read notes, bump `@terreno/*`, test, delegate Expo SDK steps to the upgrading-expo skill |
|
|
557
|
-
|
|
558
|
-
### Resources
|
|
559
|
-
|
|
560
|
-
Read-only markdown, loaded once at startup from `<docs root>/resources/` (see
|
|
561
|
-
`TERRENO_MCP_DOCS_DIR`). Restart the server to pick up changes.
|
|
562
|
-
|
|
563
|
-
| URI | Name | Source |
|
|
564
|
-
|-----|------|--------|
|
|
565
|
-
| `terreno://docs/overview` | Terreno Overview | `overview.md` |
|
|
566
|
-
| `terreno://docs/api` | @terreno/api Documentation | `api.md` |
|
|
567
|
-
| `terreno://docs/ui` | @terreno/ui Documentation | `ui.md` |
|
|
568
|
-
| `terreno://docs/syncdb` | @terreno/syncdb Documentation | `syncdb.md` |
|
|
569
|
-
| `terreno://docs/rtk` | @terreno/rtk Documentation (legacy) | `rtk.md` |
|
|
570
|
-
| `terreno://docs/patterns` | Terreno Patterns & Best Practices | `patterns.md` |
|
|
571
|
-
| `terreno://docs/ui/components` | @terreno/ui Component Reference | Generated from `ui-types-documentation.json` |
|
|
572
|
-
| `terreno://docs/ui/components/<slug>` | `<Component> Component` | One per component |
|
|
573
|
-
|
|
574
|
-
The two component rows exist only when `ui-types-documentation.json` is bundled.
|
|
575
|
-
|
|
576
|
-
### Rate limiting
|
|
577
|
-
|
|
578
|
-
The hosted server limits its JSON-RPC routes per client IP: `/mcp` (all methods) and `POST /` share
|
|
579
|
-
one bucket. The `GET /` health check is never limited. The local stdio server has no limit.
|
|
580
|
-
|
|
581
|
-
- **Default:** 120 requests per 60 seconds per client IP, a fixed window. Search, codegen, and docs
|
|
582
|
-
calls are cheap per call (the search index is built once at startup), and an agent session makes
|
|
583
|
-
a few dozen calls a minute, so the default leaves room for several agents behind one NAT while
|
|
584
|
-
capping one abusive client at about 2 requests per second.
|
|
585
|
-
- **Configure:** `TERRENO_MCP_RATE_LIMIT_MAX` (`0` turns the limit off, for example in local
|
|
586
|
-
development) and `TERRENO_MCP_RATE_LIMIT_WINDOW_MS`. An invalid value stops the server at startup
|
|
587
|
-
rather than running unlimited.
|
|
588
|
-
- **Per instance:** counters live in memory on each Cloud Run instance. With `N` instances, one
|
|
589
|
-
client can make up to `N` times the limit in a window if its requests land on different
|
|
590
|
-
instances.
|
|
591
|
-
- **Client IP:** on Cloud Run the server trusts one proxy hop, so the client IP is the address the
|
|
592
|
-
Google Front End appended to `X-Forwarded-For`. Entries a client writes into that header itself
|
|
593
|
-
are ignored, so a forged header cannot switch buckets. Off Cloud Run no proxy is trusted and the
|
|
594
|
-
socket address is used. Set `TERRENO_MCP_TRUST_PROXY_HOPS` when you add a proxy layer (for
|
|
595
|
-
example `2` behind an external HTTPS load balancer).
|
|
596
|
-
|
|
597
|
-
A request over the limit gets HTTP `429` with `Retry-After`, `RateLimit`, and `RateLimit-Policy`
|
|
598
|
-
headers and a JSON-RPC error body. `id` echoes the request id when the body is a single request
|
|
599
|
-
with a string or number id; otherwise it is `null`.
|
|
600
|
-
|
|
601
|
-
``````json
|
|
342
|
+
``````typescript
|
|
602
343
|
{
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
344
|
+
modelName: string; // Model name (PascalCase)
|
|
345
|
+
fields: Array<{
|
|
346
|
+
name: string;
|
|
347
|
+
type: "text" | "number" | "boolean" | "date" | "select";
|
|
348
|
+
required?: boolean;
|
|
349
|
+
options?: string[]; // For select fields
|
|
350
|
+
}>;
|
|
610
351
|
}
|
|
611
352
|
``````
|
|
612
353
|
|
|
613
|
-
|
|
614
|
-
should wait `retryAfterSeconds` (or `Retry-After`) before retrying.
|
|
615
|
-
|
|
616
|
-
## Local server (`terreno-mcp-local`)
|
|
617
|
-
|
|
618
|
-
### Running the local server
|
|
619
|
-
|
|
620
|
-
Run it from the app repository root with `bunx -p @terreno/mcp terreno-mcp-local`. The bin and the
|
|
621
|
-
package have different names, so `bunx` needs `-p` unless `@terreno/mcp` is already installed in
|
|
622
|
-
the project (as in this monorepo). The bin is
|
|
623
|
-
`#!/usr/bin/env bun`, so it needs Bun; the `browser` tool needs Bun 1.4 or newer. It registers tools
|
|
624
|
-
only.
|
|
625
|
-
|
|
626
|
-
Project root discovery (`src/local/projectRoot.ts`): `TERRENO_PROJECT_ROOT` when set. Otherwise it
|
|
627
|
-
walks up to 20 directories from the working directory to the first directory with a `package.json`
|
|
628
|
-
and both a backend workspace (`backend/` or `example-backend/`) and a frontend workspace
|
|
629
|
-
(`frontend/` or `example-frontend/`), or one of them plus a non-empty `workspaces` array. With no
|
|
630
|
-
match it uses the working directory. Bootstrap names win when both exist.
|
|
631
|
-
|
|
632
|
-
Errors: a refused or invalid call usually returns explanatory text. A thrown error (for example from
|
|
633
|
-
`browser`, or a database exception) becomes a JSON-RPC error with code `-32603` and the error
|
|
634
|
-
message. An unknown tool name returns the text `Unknown tool: <name>`.
|
|
635
|
-
|
|
636
|
-
### Local tools
|
|
637
|
-
|
|
638
|
-
All schemas set `additionalProperties: false`. Every tool returns one text block, JSON for most
|
|
639
|
-
tools. The server does not validate arguments against the schema: an unknown argument, such as
|
|
640
|
-
`projection` on `database_query`, is ignored, not rejected. Check a result against the parameter
|
|
641
|
-
table when it looks unfiltered.
|
|
642
|
-
|
|
643
|
-
| Tool | Purpose | Gated by `TERRENO_MCP_EVAL` |
|
|
644
|
-
|------|---------|------|
|
|
645
|
-
| [`application_info`](#application_info) | Workspace packages and key dependency versions | no |
|
|
646
|
-
| [`database_schema`](#database_schema) | Mongo collections, indexes, counts, model excerpts | no |
|
|
647
|
-
| [`database_query`](#database_query) | Read-only Mongo queries | no |
|
|
648
|
-
| [`read_logs`](#read_logs) | Merged backend, browser, Metro, and app log tail | no |
|
|
649
|
-
| [`last_error`](#last_error) | Newest error-level log entry | no |
|
|
650
|
-
| [`get_client_state`](#get_client_state) | RTK Query and SyncDB state of the running app | no |
|
|
651
|
-
| [`get_rtk_state`](#get_rtk_state) | Deprecated alias of `get_client_state` | no |
|
|
652
|
-
| [`get_syncdb_state`](#get_syncdb_state) | SyncDB client state | no |
|
|
653
|
-
| [`syncdb_snapshot`](#syncdb_snapshot) | Capture and compare SyncDB snapshots | no |
|
|
654
|
-
| [`syncdb_action`](#syncdb_action) | Change SyncDB client state | yes, every action |
|
|
655
|
-
| [`evaluate`](#evaluate) | Run JavaScript in the app runtime | yes |
|
|
656
|
-
| [`navigate`](#navigate) | Navigate the app with expo-router | yes |
|
|
657
|
-
| [`browser`](#browser) | Drive a headless WebView | only the `evaluate` action |
|
|
658
|
-
|
|
659
|
-
Example outputs below are real tool output, shortened with `…`. Where an output needs a running
|
|
660
|
-
Hermes app, which the capture environment did not have, the section says so and shows only the
|
|
661
|
-
call or the failure output.
|
|
662
|
-
|
|
663
|
-
#### application_info
|
|
664
|
-
|
|
665
|
-
Read the root `package.json` and the first backend (`backend/`, then `example-backend/`) and frontend
|
|
666
|
-
(`frontend/`, then `example-frontend/`) `package.json`. It reports `@terreno/*` dependencies and
|
|
667
|
-
`expo`, `react`, `react-native`, `mongoose`, `bun`, and `@types/bun` as declared (ranges such as
|
|
668
|
-
`^57.2.0`, `catalog:`, or `workspace:*`, not resolved versions). It checks that `bun.lock` exists but
|
|
669
|
-
does not parse it. Call it at the start of a session. No parameters.
|
|
354
|
+
**Example:**
|
|
670
355
|
|
|
671
356
|
``````json
|
|
672
|
-
{
|
|
357
|
+
{
|
|
358
|
+
"modelName": "Product",
|
|
359
|
+
"fields": [
|
|
360
|
+
{"name": "title", "type": "text", "required": true},
|
|
361
|
+
{"name": "price", "type": "number", "required": true},
|
|
362
|
+
{"name": "category", "type": "select", "options": ["electronics", "books", "clothing"]}
|
|
363
|
+
]
|
|
364
|
+
}
|
|
673
365
|
``````
|
|
674
366
|
|
|
675
|
-
|
|
676
|
-
# Application info
|
|
677
|
-
|
|
678
|
-
- **projectRoot**: `…`
|
|
679
|
-
- **root package**: @terreno/root @ 1.0.0
|
|
680
|
-
- **bun.lock present**: yes
|
|
367
|
+
**Returns:**
|
|
681
368
|
|
|
682
|
-
|
|
683
|
-
-
|
|
684
|
-
-
|
|
685
|
-
- @terreno/admin-backend: workspace:*
|
|
686
|
-
…
|
|
687
|
-
- **mongoose**: catalog:
|
|
688
|
-
|
|
689
|
-
## Frontend workspace (example-frontend/)
|
|
690
|
-
…
|
|
691
|
-
- **react-native**: catalog:
|
|
692
|
-
|
|
693
|
-
## Lockfile
|
|
694
|
-
Workspace package versions are recorded under `workspaces` in `bun.lock`. Prefer installed semver over `latest` in generated code.
|
|
695
|
-
``````
|
|
369
|
+
- TextField, NumberField, SelectField components
|
|
370
|
+
- Validation logic structure
|
|
371
|
+
- Form state management pattern
|
|
696
372
|
|
|
697
|
-
|
|
373
|
+
### terreno_validate_model_schema
|
|
698
374
|
|
|
699
|
-
|
|
700
|
-
each `backend/src/models/*.ts` file (except `index.ts`), read as text. Only `backend/` is scanned,
|
|
701
|
-
not `example-backend/`. Each call connects with Mongoose and disconnects at the end.
|
|
375
|
+
Validate a Mongoose schema against Terreno conventions.
|
|
702
376
|
|
|
703
|
-
|
|
704
|
-
`<project root>/backend/.env`. `example-backend/.env` is not read.
|
|
377
|
+
**Parameters:**
|
|
705
378
|
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
``````json
|
|
712
|
-
{"name":"database_schema","arguments":{"summary":true}}
|
|
379
|
+
``````typescript
|
|
380
|
+
{
|
|
381
|
+
schemaCode: string; // Full schema code to validate
|
|
382
|
+
}
|
|
713
383
|
``````
|
|
714
384
|
|
|
715
|
-
|
|
385
|
+
**Returns:**
|
|
716
386
|
|
|
717
|
-
|
|
718
|
-
|
|
387
|
+
- List of convention violations
|
|
388
|
+
- Recommendations for fixes
|
|
389
|
+
- Severity levels (error, warning, info)
|
|
719
390
|
|
|
720
|
-
|
|
391
|
+
### terreno_validate_ui_blocks
|
|
721
392
|
|
|
722
|
-
|
|
393
|
+
Check one whole-reply YAML or JSON document. The text is the same report `terreno-blocks validate` prints: each problem is `path CODE message — fix`. A valid document with no warnings returns an empty string.
|
|
723
394
|
|
|
724
|
-
|
|
395
|
+
**Parameters:**
|
|
725
396
|
|
|
726
|
-
|
|
397
|
+
``````typescript
|
|
398
|
+
{
|
|
399
|
+
document: string; // Required — the YAML or JSON document
|
|
400
|
+
}
|
|
727
401
|
``````
|
|
728
402
|
|
|
729
|
-
|
|
403
|
+
**Returns:**
|
|
730
404
|
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
resolution as `database_schema`. Results are returned unredacted, so avoid collections that hold
|
|
734
|
-
credentials (Better Auth keeps password hashes in `account`).
|
|
405
|
+
- The CLI report, including a trailing newline when there is at least one line
|
|
406
|
+
- An empty string when the document is valid and has no warnings
|
|
735
407
|
|
|
736
|
-
|
|
737
|
-
|-----------|------|----------|-------------|
|
|
738
|
-
| `collection` | string | yes | Collection name |
|
|
739
|
-
| `operation` | `find` \| `aggregate` \| `countDocuments` \| `distinct` | yes | Operation |
|
|
740
|
-
| `filter` | object | no | Query for `find`, `countDocuments`, `distinct`. Rejected anywhere it contains `$where`, `$function`, or `$accumulator`. |
|
|
741
|
-
| `pipeline` | object[] | no | Stages for `aggregate`. Rejected anywhere it contains `$out`, `$merge`, or `$function`. |
|
|
742
|
-
| `field` | string | for `distinct` | Field to collect |
|
|
743
|
-
| `limit` | number | no | Rows or distinct values returned. Default 50, clamped 1–200. |
|
|
408
|
+
### terreno_bootstrap_ai_rules
|
|
744
409
|
|
|
745
|
-
|
|
746
|
-
`{collection, count}`; `distinct` returns `{collection, field, truncated, values}`.
|
|
410
|
+
Scaffold AI coding assistant rules (AGENTS.md, Cursor/Windsurf rules, Copilot instructions, rulesync config).
|
|
747
411
|
|
|
748
|
-
|
|
749
|
-
{"name":"database_query","arguments":{"collection":"todos","operation":"aggregate","pipeline":[{"$group":{"_id":"$completed","count":{"$sum":1}}},{"$sort":{"_id":1}}]}}
|
|
750
|
-
``````
|
|
412
|
+
**Parameters:**
|
|
751
413
|
|
|
752
|
-
``````
|
|
414
|
+
``````typescript
|
|
753
415
|
{
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
"count": 2
|
|
760
|
-
}
|
|
761
|
-
]
|
|
416
|
+
appName: string;
|
|
417
|
+
appDisplayName: string;
|
|
418
|
+
description?: string;
|
|
419
|
+
/** Optional — which @terreno/* packages to merge into rules. Use ids like `api`, `ui`, `syncdb`, `admin-backend`, `admin-frontend`, or `@terreno/api`. Omit or pass only what the app uses so admin guidelines stay out of projects without the admin panel. */
|
|
420
|
+
packages?: string[];
|
|
762
421
|
}
|
|
763
422
|
``````
|
|
764
423
|
|
|
765
|
-
|
|
766
|
-
{"name":"database_query","arguments":{"collection":"todos","operation":"aggregate","pipeline":[{"$out":"x"}]}}
|
|
767
|
-
``````
|
|
424
|
+
Guideline bodies are composed from per-package `.ai/guidelines/core.md` files, copied into this package at build time (`bun run sync-package-guidelines` in `mcp-server/`).
|
|
768
425
|
|
|
769
|
-
|
|
770
|
-
Pipeline rejected: `$out`, `$merge`, and `$function` are not allowed.
|
|
771
|
-
``````
|
|
426
|
+
**Returns:** Rules files and instructions for installing/syncing with rulesync.
|
|
772
427
|
|
|
773
|
-
|
|
774
|
-
{"name":"database_query","arguments":{"collection":"todos","operation":"find","filter":{"$where":"true"}}}
|
|
775
|
-
``````
|
|
428
|
+
### terreno_install_admin
|
|
776
429
|
|
|
777
|
-
|
|
778
|
-
Filter rejected: `$where`, `$function`, and `$accumulator` are not allowed.
|
|
779
|
-
``````
|
|
430
|
+
Generate admin panel integration for `@terreno/admin-backend` and `@terreno/admin-frontend`.
|
|
780
431
|
|
|
781
|
-
|
|
432
|
+
**Parameters:** Model configurations with `modelName`, `routePath`, `displayName`, `listFields`, etc.
|
|
782
433
|
|
|
783
|
-
|
|
434
|
+
**Returns:** Frontend screen files and backend/frontend setup snippets. The generated
|
|
435
|
+
`admin/_layout.tsx` wraps the routes in `AdminProvider` with `apiOrigin={baseUrl}` (from
|
|
436
|
+
`@terreno/syncdb/config`) and `getAuthHeaders` reading `authProvider.getToken()` from the
|
|
437
|
+
scaffold's `frontend/store/syncdb.ts`. No `@terreno/rtk` import.
|
|
784
438
|
|
|
785
|
-
|
|
786
|
-
|--------|-------|-----------|-------|
|
|
787
|
-
| `backend` | `app.log` in each existing `<root>/backend/.terreno/logs`, `<root>/example-backend/.terreno/logs`, `<root>/.terreno/logs` | `@terreno/api` logger JSONL transport (see `TERRENO_LOG_FILE`) at `<backend cwd>/.terreno/logs/app.log` | No `stack` field: `logger.error` stacks are inside `message` |
|
|
788
|
-
| `browser` | `browser.log` in the same directories | [`POST /__terreno/browser-logs`](api.md#development-browser-log-ingestion), fed by `installTerrenoDevConsoleLogger` from `@terreno/syncdb` | `console.error` entries carry no stack; uncaught errors carry `stack`. A render error caught by an error boundary is a `console.error` entry: no `stack`, unformatted `%o`/`%s` placeholders, and the component name in `message` |
|
|
789
|
-
| `metro` | In-memory ring (2000) from Metro's `ws://<metro>/events` | Metro dev server | Always empty with Expo CLI 57 (see [Metro and CDP connection](#metro-and-cdp-connection)) |
|
|
790
|
-
| `app` | In-memory ring (2000) of Hermes `Runtime.consoleAPICalled` over CDP | The running Hermes app | Needs a Hermes target; `stack` is a JSON string of the first 8 call frames; timestamps are receipt time |
|
|
439
|
+
## Prompts
|
|
791
440
|
|
|
792
|
-
|
|
793
|
-
held for the life of the MCP process. Earlier output is not captured.
|
|
441
|
+
Multi-step workflow prompts that guide AI assistants through complex tasks.
|
|
794
442
|
|
|
795
|
-
|
|
796
|
-
|-----------|------|----------|-------------|
|
|
797
|
-
| `sources` | string[] | no | Any of `backend`, `browser`, `metro`, `app`. Default all four. |
|
|
798
|
-
| `entries` | number | no | Default 200, clamped 1–2000. Limits lines read per file and the merged result. |
|
|
799
|
-
| `level` | string | no | Exact, case-insensitive level match, e.g. `error` |
|
|
800
|
-
| `since` | string | no | ISO-8601 instant. Drops entries before it; entries without a parseable timestamp are kept. |
|
|
443
|
+
### terreno_bootstrap
|
|
801
444
|
|
|
802
|
-
|
|
803
|
-
|----------------|---------|
|
|
804
|
-
| `connection` | Always the CDP and Metro events status (see [Metro and CDP connection](#metro-and-cdp-connection)), even when `metro` and `app` were not requested |
|
|
805
|
-
| `entries` | Each `{level, message, raw, source, timestamp}`; `raw` is the line as written |
|
|
806
|
-
| `metroHint` | Connection details for the `metro` and `app` sources requested; absent when neither was requested |
|
|
807
|
-
| `projectRoot` | Resolved project root |
|
|
808
|
-
|
|
809
|
-
``````json
|
|
810
|
-
{"name":"read_logs","arguments":{"level":"error","entries":3}}
|
|
811
|
-
``````
|
|
812
|
-
|
|
813
|
-
``````json
|
|
814
|
-
{
|
|
815
|
-
"connection": "CDP: Error: No debuggable Hermes/React Native target with webSocketDebuggerUrl (is the app running?); Metro events: connected",
|
|
816
|
-
"entries": [
|
|
817
|
-
…,
|
|
818
|
-
{
|
|
819
|
-
"level": "error",
|
|
820
|
-
"message": "Uncaught TypeError: Cannot read properties of undefined (reading 'profile')",
|
|
821
|
-
"raw": "{\"level\":\"error\",\"message\":\"Uncaught TypeError: Cannot read properties of undefined (reading 'profile')\",\"source\":\"browser\",\"stack\":\"TypeError: Cannot read properties of undefined (reading 'profile')\\n at brokenHandler (eval at evaluate (:303:30), <anonymous>:4:19)\\n at eval (eval at evaluate (:303:30), <anonymous>:6:22)\",\"timestamp\":\"2026-10-12T00:24:58.867+00:00\"}",
|
|
822
|
-
"source": "browser",
|
|
823
|
-
"timestamp": "2026-10-12T00:24:58.867+00:00"
|
|
824
|
-
},
|
|
825
|
-
{
|
|
826
|
-
"level": "error",
|
|
827
|
-
"message": "Fallthrough error: SyntaxError: JSON Parse error: Unexpected identifier \"broken\"\nSyntaxError: JSON Parse error: Unexpected identifier \"broken\"\n at <parse> (:0)\n…",
|
|
828
|
-
"raw": "{\"level\":\"error\",\"message\":\"Fallthrough error: SyntaxError: …\",\"requestId\":\"2edcea24-66a8-40b6-821c-a62f57af91fc\",\"terrenoRequestLog\":{\"requestId\":\"2edcea24-66a8-40b6-821c-a62f57af91fc\",\"userId\":null},\"timestamp\":\"2026-10-12T00:25:13.380Z\"}",
|
|
829
|
-
"source": "backend",
|
|
830
|
-
"timestamp": "2026-10-12T00:25:13.380Z"
|
|
831
|
-
}
|
|
832
|
-
],
|
|
833
|
-
"metroHint": "connected | Error: No debuggable Hermes/React Native target with webSocketDebuggerUrl (is the app running?)",
|
|
834
|
-
"projectRoot": "/workspace"
|
|
835
|
-
}
|
|
836
|
-
``````
|
|
445
|
+
Workflow prompt for scaffolding a new Terreno app. Instructs the assistant to run `bunx create-terreno-app`, then `terreno_bootstrap_ai_rules`.
|
|
837
446
|
|
|
838
|
-
|
|
839
|
-
Hermes runtime):
|
|
447
|
+
**Arguments:**
|
|
840
448
|
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
"connection": "CDP: connected; Metro events: not connected",
|
|
844
|
-
"entries": [
|
|
845
|
-
…,
|
|
846
|
-
{"level": "info", "message": "fake app tick #94", "source": "app", "timestamp": "2026-10-12T00:47:43.238Z", "raw": "…"},
|
|
847
|
-
{"level": "error", "message": "fake app error #95", "source": "app", "timestamp": "2026-10-12T00:47:44.239Z", "raw": "{\"level\":\"error\",\"message\":\"fake app error #95\",\"source\":\"app\",\"stack\":\"[{\\\"columnNumber\\\":10,\\\"functionName\\\":\\\"tick\\\",\\\"lineNumber\\\":42,\\\"scriptId\\\":\\\"1\\\",\\\"url\\\":\\\"http://localhost:8082/index.bundle\\\"}]\",\"timestamp\":\"2026-10-12T00:47:44.239Z\"}"},
|
|
848
|
-
…
|
|
849
|
-
],
|
|
850
|
-
"metroHint": "connected",
|
|
851
|
-
"projectRoot": "/workspace"
|
|
852
|
-
}
|
|
853
|
-
``````
|
|
449
|
+
- `appName` (string) — Application name in kebab-case
|
|
450
|
+
- `appDisplayName` (string) — Human-readable display name
|
|
854
451
|
|
|
855
|
-
|
|
452
|
+
### terreno_upgrade
|
|
856
453
|
|
|
857
|
-
|
|
858
|
-
each file plus the `metro` and `app` rings. On a hit it returns the entry's `raw` line only: backend
|
|
859
|
-
lines have no `source` field, and no connection status is appended.
|
|
454
|
+
Lockstep Terreno upgrade workflow: read bundled upgrade notes, bump `@terreno/*` packages, run tests, and delegate Expo SDK steps to the official upgrading-expo skill.
|
|
860
455
|
|
|
861
|
-
|
|
862
|
-
|-----------|------|----------|-------------|
|
|
863
|
-
| `sources` | string[] | no | Any of `backend`, `browser`, `metro`, `app`. Default all four. |
|
|
456
|
+
**Arguments:** `targetVersion` (optional) — target `@terreno/*` semver; omit to mean latest stable.
|
|
864
457
|
|
|
865
|
-
|
|
866
|
-
{"name":"last_error","arguments":{"sources":["browser"]}}
|
|
867
|
-
``````
|
|
458
|
+
### terreno_create_crud_feature
|
|
868
459
|
|
|
869
|
-
|
|
870
|
-
{"level":"error","message":"Uncaught TypeError: Cannot read properties of undefined (reading 'profile')","source":"browser","stack":"TypeError: Cannot read properties of undefined (reading 'profile')\n at brokenHandler (eval at evaluate (:303:30), <anonymous>:4:19)\n at eval (eval at evaluate (:303:30), <anonymous>:6:22)","timestamp":"2026-10-12T00:24:58.867+00:00"}
|
|
871
|
-
``````
|
|
460
|
+
Generate complete CRUD feature: backend model + routes + frontend screens.
|
|
872
461
|
|
|
873
|
-
|
|
462
|
+
**Arguments:**
|
|
874
463
|
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
464
|
+
- `name` (string) — Feature name (e.g., "Product")
|
|
465
|
+
- `fields` (string) — Comma-separated fields: `title:string,price:number,active:boolean`
|
|
466
|
+
- `hasOwner` (string) — "yes" or "no" (default: "no")
|
|
878
467
|
|
|
879
|
-
|
|
468
|
+
**Workflow:**
|
|
880
469
|
|
|
881
|
-
|
|
470
|
+
1. Generate Mongoose model with type definitions
|
|
471
|
+
2. Generate API routes with permissions
|
|
472
|
+
3. Generate list screen with DataTable
|
|
473
|
+
4. Generate detail screen
|
|
474
|
+
5. Generate form screen with validation
|
|
475
|
+
6. Provide instructions for:
|
|
476
|
+
- Registering routes in `server.ts`
|
|
477
|
+
- Regenerating SDK: `bun run sdk`
|
|
478
|
+
- Adding navigation
|
|
882
479
|
|
|
883
|
-
|
|
884
|
-
(`__DEV__` only) as `globalThis.__TERRENO_STORE__`.
|
|
885
|
-
- SyncDB: clients created with `createSyncDb({debug: true})`, registered on
|
|
886
|
-
`globalThis.__TERRENO_SYNCDB__`.
|
|
480
|
+
### terreno_create_api_endpoint
|
|
887
481
|
|
|
888
|
-
|
|
889
|
-
fixed read-only expression in the app through CDP `Runtime.evaluate` (not gated, because the caller
|
|
890
|
-
cannot change the code). Keys matching `password`, `token`, `secret`, `authorization`, or `cookie`
|
|
891
|
-
(case-insensitive) are returned as `[REDACTED]`.
|
|
482
|
+
Generate custom (non-CRUD) API endpoint with OpenAPI documentation.
|
|
892
483
|
|
|
893
|
-
|
|
894
|
-
|-----------|------|----------|-------------|
|
|
895
|
-
| `slice` | string | no | RTK: `auth` (Better Auth slice, else legacy `auth`), `betterAuth`, `rtk` or `terreno-rtk`, or any top-level state key. Omit for auth plus the RTK Query cache summary. |
|
|
896
|
-
| `query` | string | no | RTK: keep cache rows whose endpoint name or serialized args contain this substring (case-insensitive) |
|
|
897
|
-
| `name` | string | no | SyncDB client name. Default the first registered client. |
|
|
898
|
-
| `collection` | string | no | SyncDB collection filter |
|
|
899
|
-
| `entityId` | string | no | SyncDB entity id filter |
|
|
900
|
-
| `includeDebugEvents` | boolean | no | SyncDB: `false` returns debug stats without event bodies |
|
|
901
|
-
| `limit` | number | no | SyncDB entities per collection. Default 500, max 2000. |
|
|
484
|
+
**Arguments:**
|
|
902
485
|
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
`
|
|
906
|
-
`layer: "none"` the response has `connection`, `hint`, and per-layer `reasons` instead.
|
|
486
|
+
- `path` (string) — Endpoint path (e.g., "/stats/summary")
|
|
487
|
+
- `method` (string) — HTTP method ("get", "post", "patch", "delete")
|
|
488
|
+
- `description` (string) — What the endpoint does
|
|
907
489
|
|
|
908
|
-
|
|
909
|
-
{"name":"get_client_state","arguments":{}}
|
|
910
|
-
``````
|
|
490
|
+
**Workflow:**
|
|
911
491
|
|
|
912
|
-
|
|
913
|
-
|
|
492
|
+
1. Generate route handler with asyncHandler
|
|
493
|
+
2. Generate OpenAPI builder configuration
|
|
494
|
+
3. Generate response types
|
|
495
|
+
4. Provide authentication setup instructions
|
|
496
|
+
5. Provide SDK regeneration instructions
|
|
914
497
|
|
|
915
|
-
|
|
916
|
-
{
|
|
917
|
-
"connection": "CDP: Error: No debuggable Hermes/React Native target with webSocketDebuggerUrl (is the app running?); Metro events: not connected",
|
|
918
|
-
"hint": "No client data layer found. For RTK Query, call `registerTerrenoDevStore(store)` from @terreno/rtk in __DEV__. For SyncDB, create the client with `createSyncDb({debug: true})`. Keep the app running; when the MCP process cannot see the app heap, start Metro so CDP can reach Hermes (see `connection`).",
|
|
919
|
-
"layer": "none",
|
|
920
|
-
"reasons": {
|
|
921
|
-
"rtk": "Error: No debuggable Hermes/React Native target with webSocketDebuggerUrl (is the app running?)",
|
|
922
|
-
"syncdb": "Error: Error: No debuggable Hermes/React Native target with webSocketDebuggerUrl (is the app running?)\nCDP: …"
|
|
923
|
-
}
|
|
924
|
-
}
|
|
925
|
-
``````
|
|
498
|
+
### terreno_create_ui_component
|
|
926
499
|
|
|
927
|
-
|
|
500
|
+
Generate reusable UI component following @terreno/ui patterns.
|
|
928
501
|
|
|
929
|
-
|
|
930
|
-
`{layer, rtk?, syncdb?}` response.
|
|
502
|
+
**Arguments:**
|
|
931
503
|
|
|
932
|
-
|
|
504
|
+
- `name` (string) — Component name (PascalCase)
|
|
505
|
+
- `type` (string) — "display" | "interactive" | "form" | "layout"
|
|
506
|
+
- `description` (string) — Component purpose
|
|
933
507
|
|
|
934
|
-
|
|
935
|
-
tombstones and pending metadata), decoded outbox, conflicts, cursors, streams, repair markers,
|
|
936
|
-
values, and debugger events. Same access path and redaction as `get_client_state`. Not gated.
|
|
508
|
+
**Workflow:**
|
|
937
509
|
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
| `includeDebugEvents` | boolean | no | `false` returns debug stats without event bodies |
|
|
944
|
-
| `limit` | number | no | Entities per collection. Default 500, max 2000. |
|
|
510
|
+
1. Generate component structure with TypeScript types
|
|
511
|
+
2. Include @terreno/ui imports (Box, Text, Button, etc.)
|
|
512
|
+
3. Add prop definitions with JSDoc
|
|
513
|
+
4. Include usage example
|
|
514
|
+
5. Provide testing setup
|
|
945
515
|
|
|
946
|
-
|
|
947
|
-
{"name":"get_syncdb_state","arguments":{"collection":"todos"}}
|
|
948
|
-
``````
|
|
516
|
+
### terreno_create_form_screen
|
|
949
517
|
|
|
950
|
-
|
|
951
|
-
reason (shown without a Hermes app; a populated response is not shown):
|
|
518
|
+
Generate form screen with validation and error handling.
|
|
952
519
|
|
|
953
|
-
|
|
954
|
-
Error: Error: No debuggable Hermes/React Native target with webSocketDebuggerUrl (is the app running?)
|
|
955
|
-
CDP: Error: No debuggable Hermes/React Native target with webSocketDebuggerUrl (is the app running?); Metro events: not connected
|
|
956
|
-
``````
|
|
520
|
+
**Arguments:**
|
|
957
521
|
|
|
958
|
-
|
|
522
|
+
- `name` (string) — Screen name (e.g., "CreateProduct")
|
|
523
|
+
- `modelName` (string) — Model being created/edited
|
|
524
|
+
- `fields` (string) — Comma-separated: `title:text,price:number,active:boolean`
|
|
959
525
|
|
|
960
|
-
|
|
961
|
-
and are lost when it exits. A capture keeps the full mergeable TinyBase content privately for a later
|
|
962
|
-
`syncdb_action` `mergeSnapshot`; returned state is redacted. Not gated.
|
|
526
|
+
**Workflow:**
|
|
963
527
|
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
| `snapshotId` | string | for `get`, `compare`, `delete` | Snapshot id from `capture` or `list` |
|
|
971
|
-
| `otherSnapshotId` | string | for `compare` | Second snapshot. `compare` returns up to 200 path diffs. |
|
|
528
|
+
1. Generate screen component with Page layout
|
|
529
|
+
2. Add form fields from @terreno/ui
|
|
530
|
+
3. Include validation logic
|
|
531
|
+
4. Add generated `store/apiSdk.ts` mutation hooks (or syncdb `useMutate` for synced collections)
|
|
532
|
+
5. Add loading/error/success states
|
|
533
|
+
6. Provide navigation setup
|
|
972
534
|
|
|
973
|
-
|
|
974
|
-
{"name":"syncdb_snapshot","arguments":{"action":"list"}}
|
|
975
|
-
``````
|
|
535
|
+
### terreno_add_authentication
|
|
976
536
|
|
|
977
|
-
|
|
978
|
-
[]
|
|
979
|
-
``````
|
|
537
|
+
Generate authentication setup for new projects.
|
|
980
538
|
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
Change a live SyncDB client, then return `{action, client, result, state}` with the redacted state
|
|
984
|
-
after the change. Every action requires `TERRENO_MCP_EVAL`.
|
|
985
|
-
|
|
986
|
-
| Parameter | Type | Required | Description |
|
|
987
|
-
|-----------|------|----------|-------------|
|
|
988
|
-
| `action` | enum | yes | `mutate`, `setLocalEntity`, `deleteLocalEntity`, `flush`, `reconcile`, `forceResync`, `resolveConflict`, `retryFailed`, `goOffline`, `goOnline`, `clearDebug`, `mergeSnapshot` |
|
|
989
|
-
| `name` | string | no | Client name |
|
|
990
|
-
| `collection`, `id` | string | no | Target row for `mutate`, `setLocalEntity`, `deleteLocalEntity` |
|
|
991
|
-
| `operation` | `create` \| `update` \| `delete` | no | For `mutate` |
|
|
992
|
-
| `data` | object | no | Row data for `mutate`, `setLocalEntity` |
|
|
993
|
-
| `maxAttempts` | number | no | For `mutate` |
|
|
994
|
-
| `deleted` | boolean | no | For `setLocalEntity` |
|
|
995
|
-
| `seq` | number | no | For `setLocalEntity` |
|
|
996
|
-
| `stream` | string | no | For `setLocalEntity` |
|
|
997
|
-
| `mutationId` | string | no | For `resolveConflict` |
|
|
998
|
-
| `strategy` | `useServer` \| `keepMine` | no | For `resolveConflict` |
|
|
999
|
-
| `entityId` | string | no | For `retryFailed` |
|
|
1000
|
-
| `snapshotId` | string | no | For `mergeSnapshot`; must belong to the same client |
|
|
539
|
+
**Arguments:**
|
|
1001
540
|
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
``````
|
|
541
|
+
- `strategies` (string) — Comma-separated: "email", "github", "google"
|
|
542
|
+
- `includeRefreshToken` (string) — "yes" or "no" (default: "yes")
|
|
1005
543
|
|
|
1006
|
-
|
|
544
|
+
**Workflow:**
|
|
1007
545
|
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
546
|
+
1. Configure User model with passport-local-mongoose
|
|
547
|
+
2. Set up auth routes in backend
|
|
548
|
+
3. Wire `SessionProvider` / `useSession` from `@terreno/syncdb/auth` in the frontend
|
|
549
|
+
4. Generate login screen
|
|
550
|
+
5. Generate signup screen
|
|
551
|
+
6. Set up token storage
|
|
552
|
+
7. Provide environment variable list
|
|
1011
553
|
|
|
1012
|
-
|
|
554
|
+
### terreno_migrate_to_terreno_app
|
|
1013
555
|
|
|
1014
|
-
|
|
1015
|
-
(`awaitPromise`, `returnByValue`). Returns `{result, status}` or `{error, status}`, where `status` is
|
|
1016
|
-
the connection status. Requires `TERRENO_MCP_EVAL`.
|
|
556
|
+
Guide for migrating from `setupServer` to the `TerrenoApp` fluent API pattern.
|
|
1017
557
|
|
|
1018
|
-
|
|
1019
|
-
|-----------|------|----------|-------------|
|
|
1020
|
-
| `code` | string | yes | Expression to evaluate |
|
|
558
|
+
**Arguments:**
|
|
1021
559
|
|
|
1022
|
-
|
|
1023
|
-
{"name":"evaluate","arguments":{"code":"1 + 1"}}
|
|
1024
|
-
``````
|
|
560
|
+
- `serverFile` (string, optional) — Path to server file to migrate (e.g., `src/server.ts`)
|
|
1025
561
|
|
|
1026
|
-
|
|
562
|
+
### terreno_style_guide
|
|
1027
563
|
|
|
1028
|
-
|
|
1029
|
-
Refused: set `TERRENO_MCP_EVAL=1` to opt in to `Runtime.evaluate` (arbitrary JS in the app runtime).
|
|
1030
|
-
``````
|
|
564
|
+
Returns comprehensive code style guide from project documentation.
|
|
1031
565
|
|
|
1032
|
-
|
|
566
|
+
**No arguments required.**
|
|
1033
567
|
|
|
1034
|
-
|
|
1035
|
-
`push(path)` when `navigate` is missing. Returns `{result, status}` with `result` like
|
|
1036
|
-
`{ok, method}`, or `{error, status}`. Requires `TERRENO_MCP_EVAL`.
|
|
568
|
+
**Returns:**
|
|
1037
569
|
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
570
|
+
- TypeScript conventions
|
|
571
|
+
- React/React Native patterns
|
|
572
|
+
- Backend API conventions
|
|
573
|
+
- Testing practices
|
|
574
|
+
- Logging guidelines
|
|
1041
575
|
|
|
1042
|
-
|
|
1043
|
-
{"name":"navigate","arguments":{"path":"/settings"}}
|
|
1044
|
-
``````
|
|
576
|
+
## Environment Variables
|
|
1045
577
|
|
|
1046
|
-
|
|
578
|
+
### Server Configuration
|
|
1047
579
|
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
580
|
+
| Variable | Default | Description |
|
|
581
|
+
|----------|---------|-------------|
|
|
582
|
+
| `PORT` | `8080` | HTTP server port |
|
|
583
|
+
| `MCP_HOST` or `HOST` | `0.0.0.0` | Server host address |
|
|
584
|
+
| `TERRENO_MCP_DOCS_DIR` | `../docs` | Path to documentation directory (relative to dist/) |
|
|
585
|
+
| `TERRENO_PROJECT_ROOT` | nearest Terreno project root | Override local package, database, and log discovery |
|
|
586
|
+
| `TERRENO_METRO_URL` | Frontend script port or `http://localhost:8082` | Metro origin used for `/events` and CDP discovery |
|
|
587
|
+
| `TERRENO_MCP_EVAL` | Disabled | Set to `1` to enable local MCP `evaluate`, `navigate`, and SyncDB state-changing actions |
|
|
588
|
+
| `TERRENO_BROWSER_LOGS` | Enabled only when `NODE_ENV=development` | Set to `true` to opt in in another non-production environment or `false` to disable; production rejects the route, and non-loopback clients must authenticate |
|
|
1051
589
|
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
Drive a headless page with Bun's built-in `Bun.WebView`: system WebKit on macOS; on Linux and
|
|
1055
|
-
Windows, Chrome, Chromium, or Edge over the Chrome DevTools Protocol (set `BUN_CHROME_PATH` when Bun
|
|
1056
|
-
cannot find one). One session per MCP process; calls are serialized. Use it to exercise a changed web
|
|
1057
|
-
flow, then `snapshot` and `screenshot` as proof, then `close`.
|
|
1058
|
-
|
|
1059
|
-
| Action | Uses | Notes |
|
|
1060
|
-
|--------|------|-------|
|
|
1061
|
-
| `open` | `url` (required), `width` (1280), `height` (720), `dataDir` | `http:`/`https:` only. Closes any open session. Storage is ephemeral unless `dataDir`, which must be under the project root. |
|
|
1062
|
-
| `click` | `selector` (required), `timeout` | `timeout` is the selector wait in ms |
|
|
1063
|
-
| `type` | `text`, `selector`, `timeout` | Clicks `selector` first when given |
|
|
1064
|
-
| `press` | `key` (required), `modifiers` | `modifiers`: `Shift`, `Control`, `Alt`, `Meta` |
|
|
1065
|
-
| `scroll` | `selector` or `x`/`y` | Scrolls to `selector`, else by the pixel delta |
|
|
1066
|
-
| `evaluate` | `code` (required) | Gated by `TERRENO_MCP_EVAL`; without it the call fails with JSON-RPC error `-32603` ``Refused: set `TERRENO_MCP_EVAL=1` to enable arbitrary JavaScript in the WebView.`` |
|
|
1067
|
-
| `snapshot` | none | Up to 200 visible interactive elements with a usable `selector`, plus page text (20 000 chars). Password input values are `[REDACTED]`. |
|
|
1068
|
-
| `screenshot` | `output` (required), `quality` | `.png`, `.jpg`/`.jpeg`, or `.webp` (other extensions write PNG). Path must be under the project root or `/opt/cursor/artifacts`. |
|
|
1069
|
-
| `back`, `forward`, `reload` | none | History navigation |
|
|
1070
|
-
| `wait` | `timeout` | Sleeps `timeout` ms (default 1000) |
|
|
1071
|
-
| `close` | none | Ends the session |
|
|
1072
|
-
|
|
1073
|
-
Results are JSON with `action`, `ok`, and the page `title` and `url`, plus action-specific fields.
|
|
1074
|
-
Calling any page action before `open` fails with `No browser session. Run the open action first.`
|
|
590
|
+
**Example:**
|
|
1075
591
|
|
|
1076
|
-
``````
|
|
1077
|
-
|
|
1078
|
-
{"name":"browser","arguments":{"action":"snapshot"}}
|
|
1079
|
-
{"name":"browser","arguments":{"action":"screenshot","output":"artifacts/app.png"}}
|
|
1080
|
-
{"name":"browser","arguments":{"action":"close"}}
|
|
592
|
+
``````bash
|
|
593
|
+
PORT=3001 HOST=localhost bun run start
|
|
1081
594
|
``````
|
|
1082
595
|
|
|
1083
|
-
|
|
1084
|
-
{
|
|
1085
|
-
"action": "open",
|
|
1086
|
-
"ok": true,
|
|
1087
|
-
"title": "",
|
|
1088
|
-
"url": "http://localhost:8082/"
|
|
1089
|
-
}
|
|
1090
|
-
``````
|
|
596
|
+
## Development
|
|
1091
597
|
|
|
1092
|
-
``````
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
"ok": true,
|
|
1096
|
-
"snapshot": {
|
|
1097
|
-
"elements": [
|
|
1098
|
-
…,
|
|
1099
|
-
{
|
|
1100
|
-
"ariaLabel": "Text input field",
|
|
1101
|
-
"disabled": false,
|
|
1102
|
-
"name": null,
|
|
1103
|
-
"placeholder": "Password",
|
|
1104
|
-
"role": "input",
|
|
1105
|
-
"selector": "#login-screen-password-input",
|
|
1106
|
-
"text": "[REDACTED]",
|
|
1107
|
-
"type": "password"
|
|
1108
|
-
},
|
|
1109
|
-
…,
|
|
1110
|
-
{
|
|
1111
|
-
"ariaLabel": "Log In",
|
|
1112
|
-
"disabled": true,
|
|
1113
|
-
"name": null,
|
|
1114
|
-
"placeholder": null,
|
|
1115
|
-
"role": "button",
|
|
1116
|
-
"selector": "[data-testid=\"login-screen-submit-button\"]",
|
|
1117
|
-
"text": "Log In",
|
|
1118
|
-
"type": "button"
|
|
1119
|
-
},
|
|
1120
|
-
…
|
|
1121
|
-
],
|
|
1122
|
-
"text": "Welcome Back\nEmail\nPassword\n\nLog In\nForgot password?\n…",
|
|
1123
|
-
"title": "",
|
|
1124
|
-
"url": "http://localhost:8082/login"
|
|
1125
|
-
}
|
|
1126
|
-
}
|
|
1127
|
-
``````
|
|
598
|
+
``````bash
|
|
599
|
+
# Install dependencies
|
|
600
|
+
bun install
|
|
1128
601
|
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
"action": "screenshot",
|
|
1132
|
-
"ok": true,
|
|
1133
|
-
"output": "…/artifacts/app.png",
|
|
1134
|
-
"title": "",
|
|
1135
|
-
"url": "http://localhost:8082/"
|
|
1136
|
-
}
|
|
1137
|
-
``````
|
|
602
|
+
# Build
|
|
603
|
+
bun run build
|
|
1138
604
|
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
server's environment has `TERRENO_MCP_EVAL=1` or `TERRENO_MCP_EVAL=true`. The variable is read on
|
|
1143
|
-
every call; set it in the editor's server entry (`"env": {"TERRENO_MCP_EVAL": "1"}`).
|
|
1144
|
-
|
|
1145
|
-
| Gated | What it allows |
|
|
1146
|
-
|-------|----------------|
|
|
1147
|
-
| `evaluate` | Any JavaScript in the app's Hermes runtime |
|
|
1148
|
-
| `navigate` | A fixed expo-router snippet in the app runtime |
|
|
1149
|
-
| `syncdb_action` (all actions) | Writes to the app's local SyncDB store, outbox, and sync state |
|
|
1150
|
-
| `browser` `evaluate` | Any JavaScript in the WebView page |
|
|
1151
|
-
|
|
1152
|
-
The gate exists because these calls run code with the app's full privileges: its session tokens and
|
|
1153
|
-
secure storage, its network access as the signed-in user, and its local data. An agent can be steered
|
|
1154
|
-
by text it reads, including log lines and database rows, so code execution in the app is a per-process
|
|
1155
|
-
opt-in rather than a default.
|
|
1156
|
-
|
|
1157
|
-
Not gated: `get_client_state`, `get_rtk_state`, `get_syncdb_state`, and `syncdb_snapshot` also use
|
|
1158
|
-
`Runtime.evaluate` when the app is in another process, but only with fixed read expressions built by
|
|
1159
|
-
the server (caller values are JSON-encoded), and their output is redacted. `database_query` is
|
|
1160
|
-
read-only by operation allowlist and operator checks. The other `browser` actions only interact with
|
|
1161
|
-
the page as a user would.
|
|
1162
|
-
|
|
1163
|
-
### Metro and CDP connection
|
|
1164
|
-
|
|
1165
|
-
`read_logs` (`metro`, `app`), `last_error`, `get_client_state`, `get_syncdb_state`,
|
|
1166
|
-
`syncdb_snapshot`, `syncdb_action`, `evaluate`, and `navigate` share one module-level session
|
|
1167
|
-
(`src/local/metro/metroDevSession.ts`):
|
|
1168
|
-
|
|
1169
|
-
- **Metro URL:** `TERRENO_METRO_URL`, else `--port N` from the frontend workspace's `scripts.start`
|
|
1170
|
-
(or `scripts.web`), else `http://localhost:8082`.
|
|
1171
|
-
- **Target:** `GET <metro>/json/list` (4 s timeout); the first target whose title contains `hermes`,
|
|
1172
|
-
else whose description contains `react native`, else the first with a `webSocketDebuggerUrl`. A
|
|
1173
|
-
web browser tab is not a target, so the `app` source and the CDP paths need a Hermes app (dev build
|
|
1174
|
-
or Expo Go) attached to Metro.
|
|
1175
|
-
- **Origin:** the debugger socket sends `Origin: <scheme>//127.0.0.1:<Metro port>`.
|
|
1176
|
-
`@react-native/dev-middleware` rejects a socket without an Origin, and Expo CLI closes one whose
|
|
1177
|
-
host is not `127.0.0.1:<Metro port>`. A base URL that reaches Metro through a port-remapping tunnel,
|
|
1178
|
-
or a Metro whose server URL is overridden by `REACT_NATIVE_PACKAGER_HOSTNAME` or
|
|
1179
|
-
`EXPO_PACKAGER_PROXY_URL`, still fails Expo's check.
|
|
1180
|
-
- **Lifetime:** connect lazily on first use, send `Runtime.enable`, then keep the socket for the life
|
|
1181
|
-
of the MCP process. Each CDP call times out after 8 s. After a close, the next call that needs the
|
|
1182
|
-
app reconnects, with no backoff.
|
|
1183
|
-
|
|
1184
|
-
The status appears as `CDP: <cdp status>; Metro events: <events status>` in `read_logs`
|
|
1185
|
-
`connection`, in `last_error` misses, and in `get_client_state` `layer: "none"` responses.
|
|
1186
|
-
|
|
1187
|
-
| CDP status | Meaning |
|
|
1188
|
-
|------------|---------|
|
|
1189
|
-
| `not connected` | No call has needed the app yet |
|
|
1190
|
-
| `connected to <title>` | This call opened a new socket |
|
|
1191
|
-
| `connected` | This call reused the open socket |
|
|
1192
|
-
| `Error: No debuggable Hermes/React Native target with webSocketDebuggerUrl (is the app running?)` | Metro answered, but no Hermes app is attached |
|
|
1193
|
-
| `TypeError: Unable to connect. Is the computer able to access the url?` | Metro is not reachable (Bun's fetch error; the Metro URL is not included) |
|
|
1194
|
-
| `Error: CDP websocket error: …` | The debugger socket upgrade failed |
|
|
1195
|
-
| `CDP disconnected (code <code>: <reason>)` | Metro closed the socket; a `[NEW_DEBUGGER_OPENED]` reason adds a hint (see below) |
|
|
1196
|
-
| `CDP socket not open after connect` | The socket closed during connect |
|
|
1197
|
-
|
|
1198
|
-
| Metro events status | Meaning |
|
|
1199
|
-
|---------------------|---------|
|
|
1200
|
-
| `not connected` | No call has requested the `metro` source |
|
|
1201
|
-
| `connected ws://<host>/events` / `connected` | New / reused socket |
|
|
1202
|
-
| `Error: Metro /events unreachable at ws://<host>/events` | Metro is not reachable |
|
|
1203
|
-
|
|
1204
|
-
The events status is not updated when the socket later closes, so a call that skips `metro` can
|
|
1205
|
-
print a stale `connected`.
|
|
1206
|
-
|
|
1207
|
-
**`metro` source under Expo CLI 57:** the `/events` socket opens and reports `connected`, but
|
|
1208
|
-
receives nothing. Expo CLI 57.0.24 (`createEventsSocket`) registers its connection handler on one
|
|
1209
|
-
WebSocket server and serves `/events` from a second one with no handler, so no client is ever counted
|
|
1210
|
-
and no event is broadcast. The `metro` source works only with a Metro whose `/events` broadcasts,
|
|
1211
|
-
such as the React Native community CLI. Read bundler errors from the Metro terminal instead.
|
|
1212
|
-
|
|
1213
|
-
### React Native DevTools and the `app` source
|
|
1214
|
-
|
|
1215
|
-
React Native 0.86 (Terreno 57) reports `supportsMultipleDebuggers` for each app page. On a normal
|
|
1216
|
-
`expo start`, React Native DevTools and `terreno-mcp-local` attach to the app at the same time, and
|
|
1217
|
-
opening DevTools does not affect the `app` source.
|
|
1218
|
-
|
|
1219
|
-
When Metro allows one debugger per app (older React Native, or Expo running headless with
|
|
1220
|
-
`EXPO_UNSTABLE_HEADLESS=1` or in a webcontainer), opening DevTools (`j` in Metro) disconnects the
|
|
1221
|
-
MCP. A call that does not read the app then shows, verbatim:
|
|
1222
|
-
|
|
1223
|
-
``````text
|
|
1224
|
-
CDP: CDP disconnected (code 1000: [NEW_DEBUGGER_OPENED] New debugger opened for the same app instance); another debugger (such as React Native DevTools) took the session, and the next call that reads the app reconnects and disconnects it
|
|
1225
|
-
``````
|
|
605
|
+
# (Build runs sync-ui-docs, sync-versioned-docs, and sync-package-guidelines before tsc.)
|
|
606
|
+
# To refresh only bundled package AI guidelines from the monorepo:
|
|
607
|
+
# bun run sync-package-guidelines
|
|
1226
608
|
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
disconnects DevTools, which shows `[NEW_DEBUGGER_OPENED] New debugger opened for the same app
|
|
1230
|
-
instance`. App console output logged while DevTools held the connection is not in `read_logs`; the
|
|
1231
|
-
first call after recovery may return only entries from before the gap.
|
|
1232
|
-
|
|
1233
|
-
Workaround: use one or the other. Close DevTools, then call `read_logs` with `sources: ["app"]`
|
|
1234
|
-
twice: the first call reconnects, the second shows new entries. To keep DevTools open, stop calling
|
|
1235
|
-
tools that read the app, or each call takes the connection back.
|
|
1236
|
-
|
|
1237
|
-
## What the local server can and cannot see
|
|
1238
|
-
|
|
1239
|
-
The local server inspects the project from the outside. It never imports or runs consumer code in its
|
|
1240
|
-
own process: model files are read as text, and the app's runtime is reached only over Metro and CDP.
|
|
1241
|
-
|
|
1242
|
-
**Can see:**
|
|
1243
|
-
|
|
1244
|
-
| Surface | How |
|
|
1245
|
-
|---------|-----|
|
|
1246
|
-
| Package manifests | Root and backend/frontend workspace `package.json` files (declared ranges); `bun.lock` presence only |
|
|
1247
|
-
| MongoDB | `MONGO_URI` from the environment or `backend/.env`; collections, indexes, counts, and read-only queries |
|
|
1248
|
-
| Model source | First 80 lines of each `backend/src/models/*.ts`, as text |
|
|
1249
|
-
| Backend and browser logs | `app.log` and `browser.log` JSONL under `.terreno/logs/` in `backend/`, `example-backend/`, or the root |
|
|
1250
|
-
| Metro | `/json/list` targets and the `/events` socket |
|
|
1251
|
-
| Running Hermes app | Console output, client state, SyncDB state over CDP; code execution and navigation with `TERRENO_MCP_EVAL` |
|
|
1252
|
-
| Web app | Rendered page through the `browser` tool's own headless WebView |
|
|
1253
|
-
|
|
1254
|
-
**Cannot see:**
|
|
1255
|
-
|
|
1256
|
-
- Production or deployed environments: no remote logs, databases, or apps. Production backends do
|
|
1257
|
-
not write the JSONL log or accept browser logs.
|
|
1258
|
-
- The web app's JavaScript heap or console through CDP. A browser tab is not a Metro debug target; use
|
|
1259
|
-
`browser`, `browser.log`, and the backend log instead.
|
|
1260
|
-
- Native crash reports, device logs, or a device that is not attached to the dev server's Metro.
|
|
1261
|
-
- App console output from before the first `app` read, or while another debugger held a
|
|
1262
|
-
single-debugger session.
|
|
1263
|
-
- Metro bundler events under Expo CLI 57 (the `metro` source is empty).
|
|
1264
|
-
- The resolved dependency tree: `application_info` reports declared ranges, not installed versions.
|
|
1265
|
-
- `example-backend/.env` and `example-backend/src/models/` (database discovery reads `backend/` only).
|
|
1266
|
-
|
|
1267
|
-
## Environment variables
|
|
1268
|
-
|
|
1269
|
-
### Hosted server variables
|
|
1270
|
-
|
|
1271
|
-
| Variable | Default | Effect |
|
|
1272
|
-
|----------|---------|--------|
|
|
1273
|
-
| `PORT` | `8080` | HTTP listen port. Parsed with `parseInt`, so leading digits win (`80abc` is port 80); a value with no leading digits stops startup with `Invalid PORT value`. |
|
|
1274
|
-
| `MCP_HOST`, then `HOST` | `0.0.0.0` | Listen host |
|
|
1275
|
-
| `NODE_ENV` | unset | `production` disables console colors and warns at startup when `SENTRY_DSN` is unset |
|
|
1276
|
-
| `SENTRY_DSN` | unset (Sentry disabled) | Sentry DSN |
|
|
1277
|
-
| `APP_ENV` | `development` | Sentry `environment` |
|
|
1278
|
-
| `SENTRY_TRACES_SAMPLE_RATE` | `0.1` | Sentry trace sample rate (float) |
|
|
1279
|
-
| `TERRENO_MCP_DOCS_DIR` | `<module dir>/docs` (`dist/docs`), else `docs/` next to the executable | Root for bundled resources, prompts' markdown, the search index, and upgrade notes |
|
|
1280
|
-
| `TERRENO_HELP_API_URL` | unset | Terreno backend help API for announcements in the three update-note tools. Unset means bundled upgrade notes only. |
|
|
1281
|
-
| `TERRENO_HELP_API_TOKEN` | unset | Bearer token for `TERRENO_HELP_API_URL` |
|
|
1282
|
-
| `TERRENO_MCP_RATE_LIMIT_MAX` | `120` | JSON-RPC requests per client IP per window; `0` disables. Invalid values stop startup. See [Rate limiting](#rate-limiting). |
|
|
1283
|
-
| `TERRENO_MCP_RATE_LIMIT_WINDOW_MS` | `60000` | Rate-limit window in milliseconds (minimum 1) |
|
|
1284
|
-
| `TERRENO_MCP_TRUST_PROXY_HOPS` | `1` when `K_SERVICE` is set, else `0` | Reverse-proxy hops trusted for the client IP in `X-Forwarded-For` |
|
|
1285
|
-
| `K_SERVICE` | set by Cloud Run | Read only to choose the `TERRENO_MCP_TRUST_PROXY_HOPS` default |
|
|
1286
|
-
|
|
1287
|
-
### Local server variables
|
|
1288
|
-
|
|
1289
|
-
| Variable | Default | Effect |
|
|
1290
|
-
|----------|---------|--------|
|
|
1291
|
-
| `TERRENO_PROJECT_ROOT` | Discovered root (see [Running the local server](#running-the-local-server)) | Root for packages, database, logs, Metro URL, and browser paths |
|
|
1292
|
-
| `TERRENO_METRO_URL` | `--port` from the frontend `start`/`web` script, else `http://localhost:8082` | Metro HTTP origin for `/json/list`, `/events`, and the debugger Origin's port |
|
|
1293
|
-
| `TERRENO_MCP_EVAL` | disabled | `1` or `true` enables `evaluate`, `navigate`, `syncdb_action`, and `browser` `evaluate`. See [`TERRENO_MCP_EVAL` gate](#terreno_mcp_eval-gate). |
|
|
1294
|
-
| `MONGO_URI` | `MONGO_URI`, then `MONGODB_URI`, from `<root>/backend/.env` | MongoDB for `database_schema` and `database_query` |
|
|
1295
|
-
| `BUN_CHROME_PATH` | Bun auto-discovery | Chrome, Chromium, or Edge binary for `browser` on Linux and Windows (read by Bun, not Terreno) |
|
|
1296
|
-
|
|
1297
|
-
### App-side variables that feed the local server
|
|
1298
|
-
|
|
1299
|
-
| Variable | Read by | Default | Effect |
|
|
1300
|
-
|----------|---------|---------|--------|
|
|
1301
|
-
| `TERRENO_LOG_FILE` | `@terreno/api` logger | on when `NODE_ENV !== "production"` | Backend JSONL transport to `<cwd>/.terreno/logs/app.log` (5 MB × 3 files, level `debug`). `false`/`0` forces off, `true`/`1` forces on. A toggle, not a path. |
|
|
1302
|
-
| `TERRENO_BROWSER_LOGS` | `@terreno/api` `TerrenoApp` | on only when `NODE_ENV === "development"` | Registers `POST /__terreno/browser-logs`, which appends to `<cwd>/.terreno/logs/browser.log`. `true`/`1` opts in outside development, `false`/`0` disables; production never registers it. See [Development browser-log ingestion](api.md#development-browser-log-ingestion). |
|
|
1303
|
-
| `NODE_ENV` | `@terreno/api` | unset | Drives both defaults above |
|
|
1304
|
-
| `TERRENO_DEV_CONSOLE_LOGGER_TEST` | `@terreno/syncdb` `installTerrenoDevConsoleLogger` | unset | Test-only: `true` lets the console logger install outside `__DEV__` |
|
|
1305
|
-
|
|
1306
|
-
The full cross-package list is in [Environment variables](environment-variables.md).
|
|
609
|
+
# Watch mode (rebuilds on changes)
|
|
610
|
+
bun run dev
|
|
1307
611
|
|
|
1308
|
-
|
|
612
|
+
# Start server
|
|
613
|
+
bun run start
|
|
1309
614
|
|
|
1310
|
-
|
|
1311
|
-
# From the monorepo root
|
|
1312
|
-
bun install
|
|
1313
|
-
bun run mcp:build # sync docs + tsc + copy docs into dist/
|
|
1314
|
-
|
|
1315
|
-
# From mcp-server/
|
|
1316
|
-
bun run compile # type-check only
|
|
1317
|
-
bun run build # full artifact (sync-ui-docs, sync-versioned-docs, sync-package-guidelines, tsc, copy docs)
|
|
1318
|
-
bun run dev # hosted server with watch
|
|
1319
|
-
bun run start # hosted server from dist/ (run build first)
|
|
1320
|
-
bun run test # bun test src/
|
|
615
|
+
# Lint
|
|
1321
616
|
bun run lint
|
|
1322
|
-
``````
|
|
1323
617
|
|
|
1324
|
-
|
|
618
|
+
# Fix lint issues
|
|
619
|
+
bun run lint:fix
|
|
620
|
+
``````
|
|
1325
621
|
|
|
1326
622
|
### Docker
|
|
1327
623
|
|
|
1328
|
-
Build from the repository root, as `scripts/ci/gcp-deploy.sh mcp-prod` does. The image needs the
|
|
1329
|
-
monorepo (`api/`, `blocks/`, `ui/`, `docs/`, `website/versioned_docs/`):
|
|
1330
|
-
|
|
1331
624
|
``````bash
|
|
1332
|
-
|
|
625
|
+
# Build image
|
|
626
|
+
docker build -t terreno-mcp-server ./mcp-server
|
|
627
|
+
|
|
628
|
+
# Run container
|
|
1333
629
|
docker run --rm -p 8080:8080 terreno-mcp-server
|
|
1334
630
|
``````
|
|
1335
631
|
|
|
1336
|
-
`mcp-server/src/docs/ui-types-documentation.json` and `mcp-server/src/docs/versioned/` are
|
|
1337
|
-
git-ignored, so the builder stage generates them. `bun run --filter "@terreno/ui" types` writes the
|
|
1338
|
-
TypeDoc JSON that `terreno_get_component_docs` reads. `sync-versioned-docs` and
|
|
1339
|
-
`sync-package-guidelines` fill the `terreno_search_docs` corpus. Without that step the image served
|
|
1340
|
-
the one-component test fixture (`No component named "Badge". Examples: Button`) and searched only
|
|
1341
|
-
`resources/*.md`.
|
|
1342
|
-
|
|
1343
632
|
### Testing with MCP Inspector
|
|
1344
633
|
|
|
1345
634
|
``````bash
|
|
1346
|
-
#
|
|
1347
|
-
|
|
635
|
+
# Start server
|
|
636
|
+
bun run start
|
|
1348
637
|
|
|
1349
|
-
#
|
|
1350
|
-
|
|
1351
|
-
bunx @modelcontextprotocol/inspector
|
|
638
|
+
# In another terminal, use MCP inspector
|
|
639
|
+
npx @modelcontextprotocol/inspector bun run ./mcp-server/dist/index.js
|
|
1352
640
|
``````
|
|
1353
641
|
|
|
1354
642
|
## Architecture
|
|
@@ -1356,34 +644,29 @@ bunx @modelcontextprotocol/inspector
|
|
|
1356
644
|
``````
|
|
1357
645
|
mcp-server/
|
|
1358
646
|
├── src/
|
|
1359
|
-
│ ├── index.ts
|
|
1360
|
-
│ ├──
|
|
1361
|
-
│ ├──
|
|
1362
|
-
│ ├──
|
|
1363
|
-
│
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
│ ├── resources.ts # Documentation resources
|
|
1367
|
-
│ ├── docsRoot.ts # Bundled docs root (TERRENO_MCP_DOCS_DIR)
|
|
1368
|
-
│ ├── search/ # Docs search index
|
|
1369
|
-
│ ├── help/ # Update-note search and help API client
|
|
1370
|
-
│ ├── docs/ # Bundled markdown (resources, upgrades, guidelines)
|
|
1371
|
-
│ └── local/
|
|
1372
|
-
│ ├── index.ts # Local entry (stdio)
|
|
1373
|
-
│ ├── localServer.ts # Server and tools/list, tools/call handlers
|
|
1374
|
-
│ ├── localTools.ts # Local tool schemas and dispatch
|
|
1375
|
-
│ ├── projectRoot.ts # Project root discovery
|
|
1376
|
-
│ ├── logPaths.ts # .terreno/logs discovery
|
|
1377
|
-
│ ├── metro/ # Metro /events and CDP session
|
|
1378
|
-
│ └── tools/ # Tool implementations
|
|
1379
|
-
├── dist/ # Compiled output
|
|
1380
|
-
└── Dockerfile # Hosted server image
|
|
647
|
+
│ ├── index.ts # Express server + JSON-RPC handlers
|
|
648
|
+
│ ├── resources.ts # Documentation resource loader
|
|
649
|
+
│ ├── tools.ts # Code generation tools
|
|
650
|
+
│ ├── prompts.ts # Workflow prompts
|
|
651
|
+
│ └── docs/ # Inline documentation content
|
|
652
|
+
├── dist/ # Compiled output
|
|
653
|
+
└── Dockerfile # Container image
|
|
1381
654
|
``````
|
|
1382
655
|
|
|
656
|
+
**JSON-RPC 2.0 handlers:**
|
|
657
|
+
|
|
658
|
+
- `resources/list` — List available documentation
|
|
659
|
+
- `resources/read` — Read documentation content
|
|
660
|
+
- `tools/list` — List available tools
|
|
661
|
+
- `tools/call` — Execute a tool
|
|
662
|
+
- `prompts/list` — List available prompts
|
|
663
|
+
- `prompts/get` — Get prompt details
|
|
664
|
+
|
|
1383
665
|
## Deployment
|
|
1384
666
|
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
667
|
+
See [mcp-server/README.md](../../mcp-server/README.md#cicd) for:
|
|
668
|
+
|
|
669
|
+
- GitHub Actions workflows
|
|
670
|
+
- Google Cloud Run deployment
|
|
671
|
+
- Required secrets configuration
|
|
1389
672
|
- Workload Identity Federation setup
|