mcp-scraper 0.38.2 → 0.40.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.
Files changed (111) hide show
  1. package/README.md +5 -2
  2. package/package.json +5 -6
  3. package/dist/bin/api-server.cjs +0 -58752
  4. package/dist/bin/api-server.cjs.map +0 -1
  5. package/dist/bin/api-server.d.cts +0 -1
  6. package/dist/bin/api-server.d.ts +0 -1
  7. package/dist/bin/api-server.js +0 -38
  8. package/dist/bin/api-server.js.map +0 -1
  9. package/dist/bin/mcp-scraper-cli.cjs +0 -2671
  10. package/dist/bin/mcp-scraper-cli.cjs.map +0 -1
  11. package/dist/bin/mcp-scraper-cli.d.cts +0 -1
  12. package/dist/bin/mcp-scraper-cli.d.ts +0 -1
  13. package/dist/bin/mcp-scraper-cli.js +0 -742
  14. package/dist/bin/mcp-scraper-cli.js.map +0 -1
  15. package/dist/bin/mcp-scraper-install.cjs +0 -129
  16. package/dist/bin/mcp-scraper-install.cjs.map +0 -1
  17. package/dist/bin/mcp-scraper-install.d.cts +0 -1
  18. package/dist/bin/mcp-scraper-install.d.ts +0 -1
  19. package/dist/bin/mcp-scraper-install.js +0 -27
  20. package/dist/bin/mcp-scraper-install.js.map +0 -1
  21. package/dist/bin/mcp-stdio-server.cjs +0 -12264
  22. package/dist/bin/mcp-stdio-server.cjs.map +0 -1
  23. package/dist/bin/mcp-stdio-server.d.cts +0 -1
  24. package/dist/bin/mcp-stdio-server.d.ts +0 -1
  25. package/dist/bin/mcp-stdio-server.js +0 -135
  26. package/dist/bin/mcp-stdio-server.js.map +0 -1
  27. package/dist/bin/paa-harvest.cjs +0 -3808
  28. package/dist/bin/paa-harvest.cjs.map +0 -1
  29. package/dist/bin/paa-harvest.d.cts +0 -1
  30. package/dist/bin/paa-harvest.d.ts +0 -1
  31. package/dist/bin/paa-harvest.js +0 -44
  32. package/dist/bin/paa-harvest.js.map +0 -1
  33. package/dist/chunk-345BQXZH.js +0 -712
  34. package/dist/chunk-345BQXZH.js.map +0 -1
  35. package/dist/chunk-44HZLHDV.js +0 -52
  36. package/dist/chunk-44HZLHDV.js.map +0 -1
  37. package/dist/chunk-AZRPG43B.js +0 -617
  38. package/dist/chunk-AZRPG43B.js.map +0 -1
  39. package/dist/chunk-CB5C3BPB.js +0 -135
  40. package/dist/chunk-CB5C3BPB.js.map +0 -1
  41. package/dist/chunk-EGJKUB4Q.js +0 -276
  42. package/dist/chunk-EGJKUB4Q.js.map +0 -1
  43. package/dist/chunk-FQI5PFE7.js +0 -1866
  44. package/dist/chunk-FQI5PFE7.js.map +0 -1
  45. package/dist/chunk-FRYT3ID4.js +0 -684
  46. package/dist/chunk-FRYT3ID4.js.map +0 -1
  47. package/dist/chunk-G3P3ZDB4.js +0 -69
  48. package/dist/chunk-G3P3ZDB4.js.map +0 -1
  49. package/dist/chunk-K443GQY5.js +0 -24
  50. package/dist/chunk-K443GQY5.js.map +0 -1
  51. package/dist/chunk-N7KUTTCC.js +0 -3007
  52. package/dist/chunk-N7KUTTCC.js.map +0 -1
  53. package/dist/chunk-NGM237OO.js +0 -3410
  54. package/dist/chunk-NGM237OO.js.map +0 -1
  55. package/dist/chunk-NKCCGADE.js +0 -11285
  56. package/dist/chunk-NKCCGADE.js.map +0 -1
  57. package/dist/chunk-NNW3O6ZD.js +0 -108
  58. package/dist/chunk-NNW3O6ZD.js.map +0 -1
  59. package/dist/chunk-QZXKQB7Y.js +0 -414
  60. package/dist/chunk-QZXKQB7Y.js.map +0 -1
  61. package/dist/chunk-SFRMFGQ6.js +0 -158
  62. package/dist/chunk-SFRMFGQ6.js.map +0 -1
  63. package/dist/chunk-YCI2PNCS.js +0 -499
  64. package/dist/chunk-YCI2PNCS.js.map +0 -1
  65. package/dist/chunk-YODBNTTN.js +0 -7
  66. package/dist/chunk-YODBNTTN.js.map +0 -1
  67. package/dist/db-C5KVCOYT.js +0 -239
  68. package/dist/db-C5KVCOYT.js.map +0 -1
  69. package/dist/extract-bundle-KUBX6N6Z.js +0 -568
  70. package/dist/extract-bundle-KUBX6N6Z.js.map +0 -1
  71. package/dist/index.cjs +0 -4160
  72. package/dist/index.cjs.map +0 -1
  73. package/dist/index.d.cts +0 -413
  74. package/dist/index.d.ts +0 -413
  75. package/dist/index.js +0 -338
  76. package/dist/index.js.map +0 -1
  77. package/dist/location-data-repository-TTWF3OTM.js +0 -35
  78. package/dist/location-data-repository-TTWF3OTM.js.map +0 -1
  79. package/dist/server-5EX6XBIA.js +0 -33596
  80. package/dist/server-5EX6XBIA.js.map +0 -1
  81. package/dist/site-extract-repository-XSPJTCIL.js +0 -62
  82. package/dist/site-extract-repository-XSPJTCIL.js.map +0 -1
  83. package/dist/worker-XCPU4YSN.js +0 -142
  84. package/dist/worker-XCPU4YSN.js.map +0 -1
  85. package/docs/adr/0001-in-page-graphql-interception-for-anti-bot-scraping.md +0 -58
  86. package/docs/adr/0002-hybrid-smart-rag-vault-retrieval.md +0 -62
  87. package/docs/adr/0003-waive-unrecoverable-scheduled-model-cost.md +0 -22
  88. package/docs/adr/README.md +0 -13
  89. package/docs/final-tooling-spec.md +0 -206
  90. package/docs/hosted-location-data.md +0 -108
  91. package/docs/kernel-proxy-future-enhancements.md +0 -80
  92. package/docs/mcp-tool-craft-lint.generated.md +0 -183
  93. package/docs/mcp-tool-design-guide.md +0 -225
  94. package/docs/mcp-tool-manifest.generated.json +0 -22871
  95. package/docs/mcp-tool-quality-spec.md +0 -240
  96. package/docs/oauth-legal-review.md +0 -38
  97. package/docs/seo-crawl-report-spec.md +0 -287
  98. package/docs/specs/api-forge-spec.md +0 -234
  99. package/docs/specs/connected-services-control-plane-decoupling-spec.md +0 -1044
  100. package/docs/specs/deferred-work-spec.md +0 -86
  101. package/docs/specs/google-drive-bulk-access-and-mcp-schema-passthrough-spec.md +0 -1689
  102. package/docs/specs/kernel-stealth-captcha-test-matrix.md +0 -278
  103. package/docs/specs/main-mcp-integration-ownership-spec.md +0 -1164
  104. package/docs/specs/mcp-tool-definition-quality-audit-spec.md +0 -1602
  105. package/docs/specs/meta-ad-creative-media-resolution-spec.md +0 -31
  106. package/docs/specs/multimodal-image-memory-architecture-spec.md +0 -1022
  107. package/docs/specs/oauth-mcp-spec.md +0 -213
  108. package/docs/specs/query-fanout-transport-contract-fix.md +0 -45
  109. package/docs/specs/relationship-workspace-ai-behavior-plan.md +0 -26
  110. package/docs/specs/unified-credit-and-scheduled-execution-billing-spec.md +0 -995
  111. package/docs/tool-catalog-spec.md +0 -388
@@ -1,234 +0,0 @@
1
- # API Forge — Implementation Spec
2
-
3
- Research-grounded API design intelligence inside MCP Scraper. A database-design tool asks about entities and relationships, then emits DDL. API Forge asks about resources, operations, and consumers — then emits OpenAPI, Zod schemas, SQL DDL, and **MCP tool definitions that comply with `docs/mcp-tool-quality-spec.md`** — with every design decision groundable in live web evidence harvested by the existing scraper tools.
4
-
5
- ## The three-party design
6
-
7
- This is the core architecture decision and the creative center of the feature:
8
-
9
- | Party | Owns | Never does |
10
- |---|---|---|
11
- | **MCP Scraper server** | Methodology (phase machine, question cards), session state, research execution, artifact generation, critique rules | Conversation with the human |
12
- | **Calling LLM** (Claude, etc.) | Interviewing the human, translating answers into structured form, narrating findings | Design methodology, state |
13
- | **Scraper tools** (existing) | Evidence: PAA questions developers ask, competitor API doc conventions, domain entity discovery | — |
14
-
15
- The server returns *question cards* and *synthesis instructions*; the calling model conducts the interview and reports structured answers back. This works on every MCP host (no dependency on elicitation support) and keeps the methodology versioned server-side.
16
-
17
- ## Tool surface (5 new MCP tools)
18
-
19
- All registered in `src/mcp/paa-mcp-server.ts`, schemas in `src/mcp/mcp-tool-schemas.ts`, formatters in `src/mcp/mcp-response-formatter.ts`. All have `outputSchema` + `structuredContent` (these are chaining tools by definition). Annotations: `api_critique` is `readOnlyHint: true`; the four session tools are `readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true` (they mutate server-side session state).
20
-
21
- ### 1. `api_design_start`
22
-
23
- ```
24
- inputSchema: {
25
- name: z.string().min(1).describe('Working name of the API, e.g. "Acme Bookings API"'),
26
- purpose: z.string().min(1).describe('One-sentence purpose in the user\'s words'),
27
- domain: z.string().min(1).describe('Business domain, e.g. "salon appointment booking" — used to seed research'),
28
- research: z.boolean().default(true).describe('Run an automatic domain research pass (PAA + SERP) before the first interview card. Costs credits per the cost table.'),
29
- }
30
- ```
31
-
32
- Behavior: creates a session, optionally runs Phase-0 research (internal calls to `harvest()` with `maxQuestions: 15` and query `"${domain} api"` — direct function call, not HTTP; billed via existing `paa` ledger op), and returns the first question card.
33
-
34
- Description (model-facing, per quality spec): "Start an API design session. Returns a sessionId, optional domain research findings, and the first interview card — a batch of design questions. Interview the user conversationally using the card, then submit their answers with api_design_answer. Do not invent answers the user did not give."
35
-
36
- `outputSchema`: `{ sessionId, phase, card: CardOutput, research: { paaQuestions: string[], topCompetitorUrls: string[] } | null }`
37
-
38
- ### 2. `api_design_answer`
39
-
40
- ```
41
- inputSchema: {
42
- sessionId: z.string().min(1),
43
- answers: z.array(z.object({
44
- questionId: z.string().min(1),
45
- value: z.string().min(1).describe('The user\'s answer, verbatim or faithfully summarized'),
46
- skipped: z.boolean().default(false),
47
- })).min(1),
48
- }
49
- ```
50
-
51
- Behavior: validates answers against the current card, folds them into the `DesignModel` via per-question reducers, advances the phase machine when the card is satisfied, returns the next card (or `phase: 'complete'`). Free (no debit) — answers are state writes only.
52
-
53
- `outputSchema`: `{ sessionId, phase, accepted: number, designSummary: DesignSummaryOutput, card: CardOutput | null, complete: boolean }`
54
-
55
- ### 3. `api_design_research`
56
-
57
- ```
58
- inputSchema: {
59
- sessionId: z.string().min(1),
60
- competitorUrls: z.array(z.string().url()).max(5).optional().describe('API documentation URLs to mine for conventions (pagination idiom, error shape, naming, auth)'),
61
- topic: z.string().optional().describe('Free-form research topic, e.g. "webhook retry best practices" — runs a PAA harvest'),
62
- }
63
- ```
64
-
65
- Behavior: for each competitor URL, runs the existing `extract_url` pipeline internally, then a **deterministic convention extractor** (no server-side LLM): regex/heading analysis of the extracted Markdown detecting pagination style (`cursor|page|offset` token frequency), error envelope (`"error"`/`"errors"`/problem+json mentions), naming case (snake vs camel ratio in code blocks), auth scheme mentions. For `topic`, runs a PAA harvest. Results are stored as `evidence[]` entries on the session and returned with a `synthesisInstruction` string telling the calling model how to present findings and which open design questions the evidence bears on. Billed: `page_scrape` per URL, `paa` per question — existing ledger ops, no new rates needed.
66
-
67
- ### 4. `api_design_blueprint`
68
-
69
- ```
70
- inputSchema: {
71
- sessionId: z.string().min(1),
72
- formats: z.array(z.enum(['openapi', 'zod', 'sql', 'mcp_tools', 'readme'])).min(1)
73
- .default(['openapi', 'zod', 'sql', 'mcp_tools', 'readme']),
74
- }
75
- ```
76
-
77
- Behavior: runs the generators (below) against the materialized `DesignModel`. Allowed mid-interview (partial blueprint from whatever is designed so far — this enables the "show me where we are" loop). Returns artifacts inline as fenced code blocks in `content` plus `structuredContent.artifacts: [{ format, filename, source }]`. On stdio, each artifact is also saved through the existing `saveFullReport` path, which makes blueprints appear in the `report://` resources list for free. New rate: `api_blueprint` 1 000 mc (1 credit) per generation.
78
-
79
- ### 5. `api_critique`
80
-
81
- ```
82
- inputSchema: {
83
- openapiUrl: z.string().url().optional().describe('URL of an existing OpenAPI/Swagger document, or API docs page'),
84
- openapiSource: z.string().optional().describe('Pasted OpenAPI YAML/JSON when no URL is available'),
85
- audience: z.enum(['human', 'service', 'ai_agent']).default('ai_agent').describe('Score the API for this consumer. ai_agent applies MCP-readiness rules.'),
86
- }
87
- ```
88
-
89
- Behavior: fetch (via internal `extract_url` when URL) → parse OpenAPI → run the critique rule table → return scored findings `[{ ruleId, severity: 'P0'|'P1'|'P2', location, finding, fix }]`. The `ai_agent` audience adds the MCP-readiness rules derived from `docs/mcp-tool-quality-spec.md` (description quality, enum documentation, error actionability, schema-encoded defaults/caps). This is the standalone marketing wedge: "run our quality spec against *your* API." New rate: `api_critique` 2 000 mc.
90
-
91
- ## Reverse Forge (the second creative wedge — Phase 6, optional)
92
-
93
- `api_design_start` accepts an optional `importUrl`: point it at an existing API's docs site; the server runs `map_site_urls` + `extract_url` over the docs internally, reconstructs a partial `DesignModel` from the conventions extractor, and starts the interview at the *gaps* instead of from zero. The session then supports "extend this API with X" with consistency checks against the inferred conventions (e.g. "your existing endpoints use cursor pagination and snake_case; the new webhooks resource will follow"). Implemented as `meta.importedFrom` on the session plus a `seedDesignFromDocs(extracts: ExtractResult[]): Partial<DesignModel>` function in the conventions extractor module.
94
-
95
- ## The interview engine
96
-
97
- ### `src/forge/design-model.ts` — exact types
98
-
99
- ```ts
100
- export interface DesignField { name: string; type: 'string'|'number'|'boolean'|'timestamp'|'json'|'ref'; refEntity?: string; required: boolean; description: string }
101
- export interface DesignEntity { name: string; plural: string; identity: 'uuid'|'slug'|'int'; fields: DesignField[] }
102
- export interface DesignRelationship { from: string; to: string; kind: 'one_to_one'|'one_to_many'|'many_to_many'; ownership: 'embedded'|'referenced' }
103
- export interface DesignOperation { entity: string; verb: 'list'|'get'|'create'|'update'|'delete'|'action'; actionName?: string; idempotent: boolean; paginated: boolean; description: string }
104
- export interface DesignContracts { errorShape: 'problem_json'|'envelope'|'custom'; pagination: 'cursor'|'offset'|'none'; naming: 'snake'|'camel'; envelope: boolean }
105
- export interface DesignAuth { scheme: 'api_key'|'oauth2'|'jwt'|'none'; scopes: string[] }
106
- export interface DesignEvidence { source: 'paa'|'serp'|'competitor_doc'|'user'; url: string | null; finding: string; appliedTo: string }
107
- export interface DesignModel {
108
- meta: { name: string; purpose: string; domain: string; consumers: Array<'human'|'service'|'ai_agent'>; importedFrom?: string }
109
- entities: DesignEntity[]
110
- relationships: DesignRelationship[]
111
- operations: DesignOperation[]
112
- contracts: DesignContracts
113
- auth: DesignAuth
114
- evidence: DesignEvidence[]
115
- }
116
- ```
117
-
118
- ### `src/forge/question-cards.ts` — phase machine as data
119
-
120
- ```ts
121
- export type ForgePhase = 'consumers'|'entities'|'relationships'|'operations'|'contracts'|'auth'|'review'|'complete'
122
- export interface QuestionCard {
123
- phase: ForgePhase
124
- intro: string // one paragraph the model relays before asking
125
- questions: Array<{
126
- id: string // e.g. 'entities.list'
127
- ask: string // the question, written to be read aloud
128
- why: string // rationale the model can offer if asked
129
- expects: 'free_text'|'entity_list'|'choice'|'yes_no'
130
- choices?: string[]
131
- skippable: boolean
132
- appliesIf?: (model: DesignModel) => boolean // skip logic, e.g. m2m junction question only if any many_to_many
133
- }>
134
- }
135
- export const CARDS: Record<ForgePhase, QuestionCard>
136
- ```
137
-
138
- Phase order and headline questions (full card text lives in the file):
139
-
140
- 1. **consumers** — "Who calls this API: humans via a UI, backend services, or AI agents?" (multi-choice; `ai_agent` switches on MCP generation + agent-readability rules). "What must never be exposed?" (seeds redaction rules — mirrors this repo's vendor-concealment pattern).
141
- 2. **entities** — "Name the things your API manages, singular nouns." Then per entity: identity strategy, 3–7 core fields. Reducer: `entities.list` answer is parsed as comma/newline-separated nouns; per-entity follow-up cards are generated dynamically (`entities.fields.{name}`).
142
- 3. **relationships** — for each entity pair that co-occurred in answers: "Does an X own many Y?" Cardinality + embedded-vs-referenced.
143
- 4. **operations** — per entity: which of list/get/create/update/delete, plus domain actions ("cancel a booking" → `POST /bookings/{id}/cancel`, `idempotent: false`).
144
- 5. **contracts** — pagination, error shape, naming. **This is where research lands**: if the session has competitor evidence, the card's `intro` includes "Competitors X and Y both use cursor pagination" and the question defaults accordingly.
145
- 6. **auth** — scheme + scopes; if consumers includes `ai_agent`, ask about per-call cost/metering (seeds a credits-style design like this repo's).
146
- 7. **review** — the server returns a `DesignSummary`; the model walks the user through it; any "change X" answers route back to the owning phase.
147
-
148
- ### `src/forge/interview-engine.ts`
149
-
150
- ```ts
151
- export function nextCard(model: DesignModel, phase: ForgePhase): { card: QuestionCard | null; phase: ForgePhase }
152
- export function applyAnswers(model: DesignModel, phase: ForgePhase, answers: Answer[]): { model: DesignModel; errors: string[] }
153
- export function designSummary(model: DesignModel): DesignSummaryOutput
154
- ```
155
-
156
- Pure functions — no I/O — so the whole engine is unit-testable with golden sessions.
157
-
158
- ## Generators — `src/forge/generators/`
159
-
160
- Each is `(model: DesignModel) => { filename: string; source: string }`, pure, individually golden-tested.
161
-
162
- - `openapi.ts` — OpenAPI 3.1 YAML. Paths from operations (`GET /bookings`, `POST /bookings/{id}/cancel`), components.schemas from entities, error responses per `contracts.errorShape`, pagination params per `contracts.pagination`, securitySchemes per auth.
163
- - `zod.ts` — one Zod schema per entity + per-operation input schemas, naming per `contracts.naming`.
164
- - `sql.ts` — SQLite-flavored DDL: one table per entity, junction tables for `many_to_many`, FK columns for `referenced` one-to-many, `TEXT` ISO timestamps (house style of this repo's `db.ts`).
165
- - `mcp-tools.ts` — the dogfood crown: emits a `registerTool` block per operation following `docs/mcp-tool-quality-spec.md` — model-instructing description ("Use this when…"), schema-encoded defaults/caps, annotations (`readOnlyHint: true` for list/get), `outputSchema` for chaining ops, error-shape guidance. Generated against the same `liveWebToolAnnotations` helper pattern used in `paa-mcp-server.ts`.
166
- - `readme.ts` — install + auth + per-endpoint docs with curl examples.
167
-
168
- ## Persistence — `src/api/db.ts` additions
169
-
170
- ```sql
171
- CREATE TABLE IF NOT EXISTS api_forge_sessions (
172
- id TEXT PRIMARY KEY,
173
- user_id INTEGER NOT NULL,
174
- name TEXT NOT NULL,
175
- phase TEXT NOT NULL DEFAULT 'consumers',
176
- status TEXT NOT NULL DEFAULT 'active',
177
- design_json TEXT NOT NULL DEFAULT '{}',
178
- created_at TEXT NOT NULL,
179
- updated_at TEXT NOT NULL
180
- );
181
- CREATE TABLE IF NOT EXISTS api_forge_events (
182
- id INTEGER PRIMARY KEY AUTOINCREMENT,
183
- session_id TEXT NOT NULL,
184
- kind TEXT NOT NULL, -- 'answers' | 'research' | 'blueprint'
185
- payload_json TEXT NOT NULL,
186
- created_at TEXT NOT NULL
187
- );
188
- ```
189
-
190
- `design_json` is the materialized DesignModel; events are the audit trail (enables replay/undo later). DB helpers: `createForgeSession`, `getForgeSession`, `updateForgeSession`, `appendForgeEvent` — same row-mapping style as `getJob`.
191
-
192
- ## Routes — `src/api/api-forge-routes.ts`
193
-
194
- `forgeApp = new Hono<ApiKeyEnv>()` mounted at `/api-forge` in `server.ts` and added to `vercel.json` rewrites (`{ "source": "/api-forge/:path*", "destination": "/api/index" }`). Five POST routes mirroring the tools; `createApiKeyAuth`; debit-before-work + refund-on-failure exactly like `maps-routes.ts`; errors in the structured `{error, error_code, retryable}` shape. Session ownership check on every route (`session.user_id === user.id` else 404).
195
-
196
- ## Rates — `src/api/rates.ts` additions
197
-
198
- ```ts
199
- api_forge_start: 2_000, // 2 credits, includes Phase-0 research overhead
200
- api_blueprint: 1_000,
201
- api_critique: 2_000,
202
- ```
203
-
204
- Plus `CREDIT_COST_CATALOG` entries with aliases (`'api design'`, `'blueprint'`, `'critique'`), `LedgerOperation.API_FORGE_START / API_BLUEPRINT / API_CRITIQUE` + paired `_REFUND` ops (the `ledger-refund-keys` test enforces pairing).
205
-
206
- ## MCP wiring
207
-
208
- - Executor: 5 methods on `IMcpToolExecutor`… **no** — these are a separate concern; add `IApiForgeToolExecutor` interface in `IMcpToolExecutor.ts` (same pattern as `ISerpIntelligenceToolExecutor`), implemented by `HttpMcpToolExecutor` (`this.call('/api-forge/start', input)` etc.).
209
- - Registration: `registerApiForgeTools(server, executor)` in `paa-mcp-server.ts`, called from both transports (these tools work identically hosted and stdio — session state is server-side).
210
- - Formatters: each returns a Markdown report (`oneBlock`) + `structuredContent`. The blueprint formatter renders each artifact as a fenced block and saves per-artifact files on stdio.
211
-
212
- ## Tests
213
-
214
- - `tests/unit/forge-interview-engine.test.ts` — phase transitions, skip logic, reducer correctness, a full golden session (fixture answers → expected DesignModel).
215
- - `tests/unit/forge-generators.test.ts` — golden outputs per generator from a fixture DesignModel; the `mcp-tools` generator output is itself grep-asserted for quality-spec markers (`readOnlyHint`, `.default(`, `.max(`).
216
- - `tests/unit/forge-conventions-extractor.test.ts` — pagination/error/naming detection from fixture doc Markdown.
217
- - `tests/unit/mcp-server-registration.test.ts` — tool count 13 → 18 (stdio) / 20 (hosted); annotations table updated.
218
- - `tests/live/mcp/api-forge.live.test.ts` — start → answer × 2 → blueprint over stdio against the test server; asserts artifacts parse (YAML loads, DDL contains `CREATE TABLE`).
219
-
220
- ## Build phases
221
-
222
- 1. **Engine** — design-model.ts, question-cards.ts, interview-engine.ts + unit tests. No I/O. (Largest thinking, smallest risk.)
223
- 2. **Persistence + routes** — db.ts tables, api-forge-routes.ts (start/answer only), rates, vercel.json rewrite.
224
- 3. **Generators** — all five + golden tests; blueprint route + tool.
225
- 4. **Research** — conventions extractor, internal harvest/extract calls, evidence folding, research tool.
226
- 5. **Critique** — rule table + tool (independent of sessions; can ship before 4 if desired).
227
- 6. **Reverse Forge** — importUrl seeding (optional, after 1–5 prove out).
228
- 7. **Release** — quality-spec Definition-of-Done sweep: README, `public/skills/mcp-scraper/skill.md` tool list, registration tests, live tests, version bump, vercel deploy then npm publish.
229
-
230
- ## Open decisions (resolve before Phase 2)
231
-
232
- 1. Session TTL/limits: cap active sessions per user (proposal: 10) and expire after 30 days (cron at `/cron/tick` already exists).
233
- 2. Should `api_design_answer` bill micro-credits to deter abuse, or stay free? (Proposal: free; starts are the gate.)
234
- 3. Server-side LLM synthesis: deliberately excluded — the calling model synthesizes, the server stays deterministic. Revisit only if convention extraction proves too weak on real competitor docs.