@harperfast/template-react-ts-studio 1.12.7 → 1.12.9

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.
Files changed (36) hide show
  1. package/.agents/skills/harper-best-practices/AGENTS.md +514 -445
  2. package/.agents/skills/harper-best-practices/rules/automatic-apis.md +96 -93
  3. package/.agents/skills/harper-best-practices/rules/deploying-to-harper-fabric.md +84 -58
  4. package/.agents/skills/harper-best-practices/rules/extending-tables.md +27 -35
  5. package/.agents/skills/harper-best-practices/rules/handling-binary-data.md +40 -39
  6. package/.agents/skills/harper-best-practices/rules/querying-rest-apis.md +93 -37
  7. package/.agents/skills/harper-best-practices/rules/schema-design-tooling.md +68 -66
  8. package/.agents/skills/harper-best-practices/rules/using-blob-datatype.md +24 -28
  9. package/.agents/skills/harper-best-practices/rules/v5-upgrade.md +98 -105
  10. package/.agents/skills/harper-best-practices/rules.manifest.yaml +28 -3
  11. package/.agents/skills/harper-local-dev/AGENTS.md +197 -0
  12. package/.agents/skills/harper-local-dev/SKILL.md +65 -0
  13. package/.agents/skills/harper-local-dev/rules/running-dev-instances-in-worktrees.md +198 -0
  14. package/.agents/skills/harper-local-dev/rules.manifest.yaml +20 -0
  15. package/.agents/skills/harper-local-dev/scripts/harper-dev.mjs +345 -0
  16. package/.agents/skills/harper-mcp/AGENTS.md +138 -26
  17. package/.agents/skills/harper-mcp/rules/enabling-mcp.md +140 -28
  18. package/agent/skills/harper-best-practices/AGENTS.md +514 -445
  19. package/agent/skills/harper-best-practices/rules/automatic-apis.md +96 -93
  20. package/agent/skills/harper-best-practices/rules/deploying-to-harper-fabric.md +84 -58
  21. package/agent/skills/harper-best-practices/rules/extending-tables.md +27 -35
  22. package/agent/skills/harper-best-practices/rules/handling-binary-data.md +40 -39
  23. package/agent/skills/harper-best-practices/rules/querying-rest-apis.md +93 -37
  24. package/agent/skills/harper-best-practices/rules/schema-design-tooling.md +68 -66
  25. package/agent/skills/harper-best-practices/rules/using-blob-datatype.md +24 -28
  26. package/agent/skills/harper-best-practices/rules/v5-upgrade.md +98 -105
  27. package/agent/skills/harper-best-practices/rules.manifest.yaml +28 -3
  28. package/agent/skills/harper-local-dev/AGENTS.md +197 -0
  29. package/agent/skills/harper-local-dev/SKILL.md +64 -0
  30. package/agent/skills/harper-local-dev/rules/running-dev-instances-in-worktrees.md +198 -0
  31. package/agent/skills/harper-local-dev/rules.manifest.yaml +20 -0
  32. package/agent/skills/harper-local-dev/scripts/harper-dev.mjs +345 -0
  33. package/agent/skills/harper-mcp/AGENTS.md +138 -26
  34. package/agent/skills/harper-mcp/rules/enabling-mcp.md +140 -28
  35. package/package.json +1 -1
  36. package/skills-lock.json +8 -2
@@ -8,56 +8,168 @@ metadata:
8
8
  sources:
9
9
  - reference/v5/mcp/overview.md
10
10
  - reference/v5/mcp/configuration.md
11
- sourceCommit: d7d2ddb120ce5f2ad39dc425f628f5a4f220c151
12
- inputHash: 236b335c4fc56602
11
+ sourceCommit: 2cfb81318f17e0aca2d600109e6ad813d2d0443e
12
+ inputHash: 53ecfa7dd46bed75
13
13
  ---
14
14
 
15
- # Enabling MCP
15
+ # Enabling and Configuring Harper MCP Server Profiles
16
16
 
17
- Instructions for exposing a Harper instance as a Model Context Protocol (MCP) server.
17
+ Instructions for the agent to enable and configure Harper's MCP server profiles (`operations` and `application`) using the `mcp:` block in `harper-config.yaml`.
18
18
 
19
19
  ## When to Use
20
20
 
21
- Use this skill when an AI client (Claude, an agent framework, or any MCP-capable tool) should talk to Harper directly — calling tools backed by your tables and Resources, reading data as MCP resources, or driving Harper operations.
21
+ Apply this rule when adding MCP support to a Harper deployment so that LLM hosts (Claude Desktop, Cursor, Zed, custom agents) can discover and invoke Harper operations and resources. Use it when configuring rate limits, session lifecycle, allow/deny lists, or durable quota policies for either MCP profile. See [connecting-clients.md](connecting-clients.md) for wiring an MCP client to a running Harper instance.
22
22
 
23
23
  ## How It Works
24
24
 
25
- Harper ships two independent MCP **profiles**, each a Streamable HTTP endpoint (MCP spec rev 2025-06-18):
25
+ 1. **Enable profiles via presence of their sub-block.** A profile is enabled by the **presence** of its sub-block under `mcp:` — there is no separate `enabled` flag. Add an empty map to enable a profile with all defaults:
26
26
 
27
- 1. **`application` profile** — the profile most apps want. Exposes your application's surface: auto-generated CRUD verb tools for `@export`ed tables, plus anything components opt in via `static mcpTools` / `static mcpPrompts` / `static mcpResources`. Mounts on the application HTTP port (default `9926`).
28
- 2. **`operations` profile** — exposes Harper's operations API as tools (user-filtered by operation permissions). Mounts on the operations port (default `9925`). Intended for administrative agents, not application clients.
27
+ ```yaml
28
+ mcp:
29
+ operations: {}
30
+ application: {}
31
+ ```
29
32
 
30
- Enable them in `harper-config.yaml` (or the equivalent `HARPER_SET_CONFIG` process env var):
33
+ - The `operations` profile mounts at `/mcp` on the **operations server** (default port `9925`).
34
+ - The `application` profile mounts at `/mcp` on the **application HTTP server** (default port `9926`).
31
35
 
32
- ```yaml
33
- mcp:
34
- application:
35
- mountPath: /mcp # path on the application HTTP port
36
- operations:
37
- mountPath: /mcp # path on the operations port
38
- ```
36
+ 2. **Configure the operations profile (`mcp.operations`).** This profile wraps Harper's operation catalog.
37
+
38
+ | Key | Type | Default | Purpose |
39
+ | ----------- | ----------------- | --------- | -------------------------------------------------------------------------------- |
40
+ | `mountPath` | `string` | `/mcp` | URL path the endpoint mounts on |
41
+ | `allow` | `array<string>` | See below | Operations exposed as MCP tools (glob or literal); **replaces** the default list |
42
+ | `deny` | `array<string>` | `[]` | Operations filtered out after `allow` is applied |
43
+ | `maxTools` | `integer` (min 1) | `200` | Max tools per `tools/list` response page |
44
+
45
+ Default `allow` list:
46
+
47
+ ```yaml
48
+ allow:
49
+ - describe_*
50
+ - list_*
51
+ - search_*
52
+ - get_job
53
+ - get_status
54
+ - get_analytics
55
+ - get_metrics
56
+ - system_information
57
+ - read_log
58
+ - read_audit_log
59
+ ```
60
+
61
+ Setting `allow` **replaces** the default — it does not merge. To expose destructive operations (e.g. `set_configuration`, `drop_table`), add them explicitly.
62
+
63
+ 3. **Configure the application profile (`mcp.application`).** This profile walks your exported `Resource` classes and generates one MCP tool per implemented REST verb. It accepts all `mcp.operations.*` keys plus:
64
+
65
+ | Key | Type | Default | Purpose |
66
+ | ------------------ | ----------------- | ------- | ------------------------------------------------------------------ |
67
+ | `searchMaxResults` | `integer` (min 1) | `1000` | Hard cap on records a `search_<resource>` tool can return per call |
68
+
69
+ 4. **Set rate limits for each profile (`mcp.<profile>.rateLimit.*`).** Token-bucket limits apply per `(session, tool)` pair and per session overall. Exhausted buckets return `result.isError = true` with `kind: "rate_limited"` — not a JSON-RPC error. See [rate-limiting.md](rate-limiting.md) for broader context.
70
+
71
+ | Key | Type | Default (operations) | Default (application) | Purpose |
72
+ | -------------------- | ----------------- | ----------------------------------- | --------------------- | ----------------------------------------------------------------- |
73
+ | `perToolPerSecond` | `number` (min 0) | `10` | `25` | Sustained per-tool refill rate; `0` disables |
74
+ | `perToolBurst` | `number` (min 0) | `20` | `50` | Burst capacity of the per-tool bucket |
75
+ | `sessionConcurrency` | `integer` (min 0) | `25` | `50` | Max concurrent `tools/call` per session |
76
+ | `sessionPerSecond` | `number` (min 0) | `100` | `200` | Sustained per-session rate across all tools |
77
+ | `perClientPerSecond` | `number` (min 0) | `0` (disabled) | `0` (disabled) | Sustained rate keyed on client identity (5.2.0+) |
78
+ | `perClientBurst` | `number` (min 0) | `perClientPerSecond` floored at `1` | same | Burst capacity of the per-client bucket |
79
+ | `identityHeader` | `string` | unset (socket IP) | unset | Trusted header supplying client identity (e.g. `x-forwarded-for`) |
80
+
81
+ `perClientPerSecond` (5.2.0+) survives session cycling. Only set `identityHeader` when a trusted proxy strips or replaces it on untrusted traffic — a client-controlled header bypasses per-client limits entirely.
39
82
 
40
- A profile is enabled by the **presence** of its config sub-block — there is no separate `enabled` flag, so `mcp: { application: {} }` alone turns the application profile on with defaults. Each profile is independent; enable only what you need. Key per-profile options:
83
+ 5. **Configure session lifecycle (`mcp.session.*`).** These settings apply to both profiles. A dropped session causes the next request bearing that session id to receive HTTP 404; the client is expected to re-`initialize`.
41
84
 
42
- - `mountPath` — path the endpoint mounts on (default `/mcp`).
43
- - `allow` / `deny` (operations profile only) — glob patterns or literal operation names selecting which operations become tools. The default is a deliberately read-only list; setting `allow` **replaces** it (no merge), so destructive operations like `set_configuration` must be opted in explicitly.
44
- - `maxTools` — page size for `tools/list` responses (default 200); overflow pages via the MCP cursor.
45
- - `rateLimit.*` — see the [Rate Limiting](rate-limiting.md) skill.
46
- - durable quotas — registered in code with `server.setMcpQuotaHandler`, not a config key; see the [Durable Quotas](durable-quotas.md) skill.
85
+ | Key | Type | Default | Purpose |
86
+ | -------------------- | ----------------- | ------- | ----------------------------------------------------------------------- |
87
+ | `idleTimeoutSeconds` | `integer` (min 1) | `1800` | Idle window before a session is TTL-evicted from `system.mcp_session` |
88
+ | `allowClientDelete` | `boolean` | `false` | When `true`, accepts client-issued `DELETE /mcp` to terminate a session |
47
89
 
48
- Version notes: the transport and tool surface shipped across 5.1.x (complete protocol surface — prompts, resources, subscriptions, completions, cancellation, progress — in 5.1.10+). Custom content resources (`mcpResources`) are 5.1.18+. Per-client rate limiting and durable quotas are 5.2.0+.
90
+ 6. **Register a durable quota handler (optional, 5.2.0+).** For cost control that survives restarts and session cycling, register a handler with `server.setMcpQuotaHandler`. The handler runs **after** in-memory buckets admit the call. Keep any backing table unexported (no `@export`). A handler that throws **denies** the call (fail-closed). The handler receives `{ identity, tool, user, profile, sessionId }` and must return `true` to allow or `{ allowed: false, message?, retryAfterSeconds? }` to deny.
49
91
 
50
- **Verify the version before relying on gated features.** Unsupported config keys (such as the `rateLimit.perClient*` security controls) are **accepted and silently ignored** by older versions — nothing errors, the feature just doesn't run. Check `serverInfo.version` in the `initialize` response (or read `harper://about`) first, and after configuring a limit, prove it denies at least once before trusting it.
92
+ 7. **Configure Origin validation for browser clients.** MCP validates the `Origin` header to defend against DNS-rebinding attacks. Validation reuses each profile's existing CORS config:
93
+ - No `Origin` header (e.g. `curl`) → always accepted.
94
+ - CORS disabled or `*` allow-list → any `Origin` accepted.
95
+ - CORS enabled with an explicit allow-list → `Origin` not in the list returns `403 Forbidden`.
96
+
97
+ For browser-exposed deployments, enable CORS with an explicit (non-`*`) allow-list on the relevant profile.
51
98
 
52
99
  ## Examples
53
100
 
54
- Minimal application-profile setup for a project with `@export`ed tables:
101
+ **Minimal — both profiles on with all defaults:**
55
102
 
56
103
  ```yaml
57
- # harper-config.yaml
58
104
  mcp:
105
+ operations: {}
106
+ application: {}
107
+ ```
108
+
109
+ **Production deployment — locked-down operations profile, raised application throughput, graceful logout:**
110
+
111
+ ```yaml
112
+ mcp:
113
+ operations:
114
+ allow:
115
+ - describe_all
116
+ - describe_database
117
+ - system_information
118
+ - get_job
119
+ rateLimit:
120
+ perToolPerSecond: 5
121
+ perToolBurst: 10
59
122
  application:
60
- mountPath: /mcp
123
+ searchMaxResults: 500
124
+ rateLimit:
125
+ perToolPerSecond: 50
126
+ perToolBurst: 100
127
+ session:
128
+ idleTimeoutSeconds: 3600
129
+ allowClientDelete: true
61
130
  ```
62
131
 
63
- An MCP client pointed at `http://<host>:9926/mcp` then sees `get_*` / `search_*` / `create_*` / `update_*` / `delete_*` tools for every exported table, RBAC-filtered per authenticated user. See the [Connecting Clients](connecting-clients.md) skill for the handshake.
132
+ **Durable quota handler backed by an internal table:**
133
+
134
+ ```graphql
135
+ # schema.graphql — internal counter, no @export
136
+ type QuotaCounter @table {
137
+ id: ID @primaryKey
138
+ used: Int
139
+ }
140
+ ```
141
+
142
+ ```javascript
143
+ // resources.js
144
+ const DAILY_LIMIT = 100;
145
+
146
+ export class Answerer extends Resource {
147
+ static mcpTools = [{ name: 'answer', description: 'Answer a question', method: 'doAnswer' }];
148
+ async doAnswer(args) {
149
+ return { answered: args?.q ?? '' };
150
+ }
151
+ }
152
+
153
+ server.setMcpQuotaHandler(async ({ identity, tool, user, profile, sessionId }) => {
154
+ if (profile !== 'application') return true;
155
+ const id = identity ?? 'unknown';
156
+ const existing = await tables.QuotaCounter.get(id);
157
+ const used = (existing?.used ?? 0) + 1;
158
+ await tables.QuotaCounter.put({ id, used });
159
+ if (used > DAILY_LIMIT) {
160
+ return { allowed: false, message: 'daily quota reached', retryAfterSeconds: 3600 };
161
+ }
162
+ return true;
163
+ });
164
+ ```
165
+
166
+ ## Notes
167
+
168
+ - The `operations` profile mounts on port `9925`; the `application` profile mounts on port `9926`. These are the default ports — change `mountPath` only if `/mcp` collides with another route.
169
+ - Setting `mcp.operations.allow` **replaces** the default list entirely. Do not add `get_*` as a glob — it exposes `get_configuration` (which can return TLS/S3/auth secrets) and other sensitive operations.
170
+ - `perClientPerSecond` (5.2.0+) is disabled by default (`0`). Enable it to prevent session-cycling abuse.
171
+ - The durable quota handler (5.2.0+) is fail-closed: a thrown error denies the call. Race-safety under concurrent workers is the handler's responsibility — use atomic read-modify-write for production counters.
172
+ - Pass `undefined` to `server.setMcpQuotaHandler` to clear a registered handler. The latest registration wins on component reload.
173
+ - Version notes: the transport and tool surface shipped across 5.1.x (complete protocol surface — prompts, resources, subscriptions, completions, cancellation, progress — in 5.1.10+). Custom content resources (`mcpResources`) are 5.1.18+. Per-client rate limiting (`perClientPerSecond`, `perClientBurst`, `identityHeader`) and the durable quota handler (`server.setMcpQuotaHandler`) are 5.2.0+. **Verify the version before relying on gated features.** Unsupported config keys (such as the `rateLimit.perClient*` security controls) are **accepted and silently ignored** by older versions — nothing errors, the feature just doesn't run. After a session is evicted, the client must re-`initialize` to establish a new session.
174
+ - See [connecting-clients.md](connecting-clients.md) for how to connect MCP clients to these endpoints.
175
+ - See [rate-limiting.md](rate-limiting.md) for broader rate-limiting context.