@cyanheads/mcp-ts-core 0.3.3 → 0.3.5
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/CLAUDE.md +1 -1
- package/README.md +7 -9
- package/biome.json +1 -1
- package/dist/mcp-server/apps/appBuilders.d.ts +9 -1
- package/dist/mcp-server/apps/appBuilders.d.ts.map +1 -1
- package/dist/mcp-server/apps/appBuilders.js +64 -2
- package/dist/mcp-server/apps/appBuilders.js.map +1 -1
- package/dist/mcp-server/resources/utils/resourceDefinition.d.ts +16 -8
- package/dist/mcp-server/resources/utils/resourceDefinition.d.ts.map +1 -1
- package/dist/mcp-server/resources/utils/resourceDefinition.js.map +1 -1
- package/dist/mcp-server/resources/utils/resourceHandlerFactory.d.ts.map +1 -1
- package/dist/mcp-server/resources/utils/resourceHandlerFactory.js +11 -1
- package/dist/mcp-server/resources/utils/resourceHandlerFactory.js.map +1 -1
- package/package.json +15 -15
- package/skills/add-app-tool/SKILL.md +54 -32
- package/skills/add-prompt/SKILL.md +16 -11
- package/skills/add-resource/SKILL.md +16 -11
- package/skills/add-service/SKILL.md +47 -6
- package/skills/add-test/SKILL.md +23 -24
- package/skills/add-tool/SKILL.md +55 -13
- package/skills/api-testing/SKILL.md +56 -10
- package/skills/api-workers/SKILL.md +9 -7
- package/skills/design-mcp-server/SKILL.md +10 -19
- package/skills/devcheck/SKILL.md +20 -6
- package/skills/field-test/SKILL.md +17 -2
- package/skills/maintenance/SKILL.md +4 -2
- package/skills/migrate-mcp-ts-template/SKILL.md +14 -12
- package/skills/polish-docs-meta/SKILL.md +4 -4
- package/skills/setup/SKILL.md +9 -9
- package/templates/AGENTS.md +6 -1
- package/templates/CLAUDE.md +6 -2
- package/templates/src/mcp-server/resources/definitions/echo-app-ui.app-resource.ts +25 -4
|
@@ -4,7 +4,7 @@ description: >
|
|
|
4
4
|
Cloudflare Workers deployment using `createWorkerHandler` from `@cyanheads/mcp-ts-core/worker`. Covers the full handler signature, binding types, CloudflareBindings extensibility, runtime compatibility guards, and wrangler.toml requirements.
|
|
5
5
|
metadata:
|
|
6
6
|
author: cyanheads
|
|
7
|
-
version: "1.
|
|
7
|
+
version: "1.1"
|
|
8
8
|
audience: external
|
|
9
9
|
type: reference
|
|
10
10
|
---
|
|
@@ -19,15 +19,15 @@ metadata:
|
|
|
19
19
|
|
|
20
20
|
```ts
|
|
21
21
|
import { createWorkerHandler } from '@cyanheads/mcp-ts-core/worker';
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
22
|
+
import { echoTool } from './mcp-server/tools/definitions/echo.tool.js';
|
|
23
|
+
import { echoResource } from './mcp-server/resources/definitions/echo.resource.js';
|
|
24
|
+
import { echoPrompt } from './mcp-server/prompts/definitions/echo.prompt.js';
|
|
25
25
|
import { initMyService } from './services/my-domain/my-service.js';
|
|
26
26
|
|
|
27
27
|
export default createWorkerHandler({
|
|
28
|
-
tools:
|
|
29
|
-
resources:
|
|
30
|
-
prompts:
|
|
28
|
+
tools: [echoTool],
|
|
29
|
+
resources: [echoResource],
|
|
30
|
+
prompts: [echoPrompt],
|
|
31
31
|
setup(core) {
|
|
32
32
|
initMyService(core.config, core.storage);
|
|
33
33
|
},
|
|
@@ -39,6 +39,8 @@ export default createWorkerHandler({
|
|
|
39
39
|
});
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
+
Fresh scaffolds register definitions directly in the entry point as shown above. If your project later adds barrel files for definitions, importing arrays from those barrels is also fine.
|
|
43
|
+
|
|
42
44
|
### Options
|
|
43
45
|
|
|
44
46
|
| Option | Type | Purpose |
|
|
@@ -4,7 +4,7 @@ description: >
|
|
|
4
4
|
Design the tool surface, resources, and service layer for a new MCP server. Use when starting a new server, planning a major feature expansion, or when the user describes a domain/API they want to expose via MCP. Produces a design doc at docs/design.md that drives implementation.
|
|
5
5
|
metadata:
|
|
6
6
|
author: cyanheads
|
|
7
|
-
version: "2.
|
|
7
|
+
version: "2.2"
|
|
8
8
|
audience: external
|
|
9
9
|
type: workflow
|
|
10
10
|
---
|
|
@@ -117,9 +117,7 @@ const gitBranch = tool('git_branch', {
|
|
|
117
117
|
```ts
|
|
118
118
|
// Workflow tool — search + local filter pipeline, not a raw API proxy
|
|
119
119
|
const findEligibleStudies = tool('clinicaltrials_find_eligible_studies', {
|
|
120
|
-
description: 'Matches patient demographics and medical profile to eligible clinical trials. '
|
|
121
|
-
+ 'Filters by age, sex, conditions, location, and healthy volunteer status. '
|
|
122
|
-
+ 'Returns ranked list of matching studies with eligibility explanations.',
|
|
120
|
+
description: 'Matches patient demographics and medical profile to eligible clinical trials. Filters by age, sex, conditions, location, and healthy volunteer status. Returns ranked list of matching studies with eligibility explanations.',
|
|
123
121
|
// handler: listStudies() → filter by eligibility → rank by location proximity → slice
|
|
124
122
|
});
|
|
125
123
|
```
|
|
@@ -142,21 +140,20 @@ The description is the LLM's primary signal for tool selection. It must answer:
|
|
|
142
140
|
|
|
143
141
|
- **Be concrete about capability.** "Search for clinical trial studies using queries and filters" beats "Interact with studies."
|
|
144
142
|
- **Include operational guidance when it matters.** If the tool has prerequisites, constraints, or gotchas the LLM needs to know, say so in the description. Don't add boilerplate workflow hints when the tool is self-explanatory.
|
|
143
|
+
- **Don't leak implementation details.** Descriptions are for the consumer, not the author. Internal endpoint paths, API call counts, internal parameter name mappings, and routing logic don't belong — describe what the tool does and when to use it, not how it's wired up.
|
|
145
144
|
|
|
146
145
|
```ts
|
|
147
146
|
// Good — describes a prerequisite the LLM must know
|
|
148
|
-
description: 'Set the session working directory for all git operations. '
|
|
149
|
-
+ 'This allows subsequent git commands to omit the path parameter.'
|
|
147
|
+
description: 'Set the session working directory for all git operations. This allows subsequent git commands to omit the path parameter.'
|
|
150
148
|
|
|
151
149
|
// Good — self-explanatory, no workflow hints needed
|
|
152
150
|
description: 'Show the working tree status including staged, unstaged, and untracked files.'
|
|
153
151
|
|
|
154
152
|
// Good — warns about constraints
|
|
155
|
-
description: 'Fetches trial results data for completed studies. '
|
|
156
|
-
+ 'Only available for studies where hasResults is true.'
|
|
153
|
+
description: 'Fetches trial results data for completed studies. Only available for studies where hasResults is true.'
|
|
157
154
|
```
|
|
158
155
|
|
|
159
|
-
|
|
156
|
+
Descriptions should be as long as needed — concise but complete. Don't artificially truncate, and don't pad with filler.
|
|
160
157
|
|
|
161
158
|
#### Parameter descriptions
|
|
162
159
|
|
|
@@ -171,14 +168,11 @@ Every `.describe()` is prompt text the LLM reads. Parameters should convey: what
|
|
|
171
168
|
```ts
|
|
172
169
|
// Good — explains cost, recommends action, names the alternative
|
|
173
170
|
fields: z.array(z.string()).optional()
|
|
174
|
-
.describe('Specific fields to return (reduces payload size). '
|
|
175
|
-
+ 'STRONGLY RECOMMENDED — without this, the full study record (~70KB each) is returned. '
|
|
176
|
-
+ 'Use full data only when you need detailed eligibility criteria, locations, or results.'),
|
|
171
|
+
.describe('Specific fields to return (reduces payload size). Without this, the full study record (~70KB each) is returned. Use full data only when you need detailed eligibility criteria, locations, or results.'),
|
|
177
172
|
|
|
178
173
|
// Good — explains what the flag does AND how to override
|
|
179
174
|
autoExclude: z.boolean().default(true)
|
|
180
|
-
.describe('Automatically exclude lock files and generated files from diff output '
|
|
181
|
-
+ 'to reduce context bloat. Set to false if you need to inspect these files.'),
|
|
175
|
+
.describe('Automatically exclude lock files and generated files from diff output to reduce context bloat. Set to false if you need to inspect these files.'),
|
|
182
176
|
|
|
183
177
|
// Good — names the format and gives one example
|
|
184
178
|
nctIds: z.union([z.string(), z.array(z.string()).max(5)])
|
|
@@ -201,8 +195,7 @@ The output schema and `format` function control what the LLM reads back. Design
|
|
|
201
195
|
output: z.object({
|
|
202
196
|
diff: z.string().describe('Unified diff output.'),
|
|
203
197
|
excludedFiles: z.array(z.string()).optional()
|
|
204
|
-
.describe('Files automatically excluded from the diff (e.g., lock files). '
|
|
205
|
-
+ 'Call again with autoExclude=false to include them.'),
|
|
198
|
+
.describe('Files automatically excluded from the diff (e.g., lock files). Call again with autoExclude=false to include them.'),
|
|
206
199
|
}),
|
|
207
200
|
```
|
|
208
201
|
|
|
@@ -244,9 +237,7 @@ When a tool wraps a complex query language or filter system, provide a simple sh
|
|
|
244
237
|
```ts
|
|
245
238
|
// text_search handles the common case; query handles everything else
|
|
246
239
|
text_search: z.string().optional()
|
|
247
|
-
.describe('Convenience shortcut: full-text search across title and abstract. '
|
|
248
|
-
+ 'Equivalent to {"_or":[{"_text_any":{"title":"..."}},{"_text_any":{"abstract":"..."}}]}. '
|
|
249
|
-
+ 'For more control, use the query parameter directly.'),
|
|
240
|
+
.describe('Convenience shortcut: full-text search across title and abstract. For structured filters or field-specific matching, use the query parameter instead.'),
|
|
250
241
|
query: z.record(z.unknown()).optional()
|
|
251
242
|
.describe('Full query object for structured filters. Supports operators: _eq, _gt, _and, _or, ...'),
|
|
252
243
|
```
|
package/skills/devcheck/SKILL.md
CHANGED
|
@@ -4,37 +4,51 @@ description: >
|
|
|
4
4
|
Lint, format, typecheck, and verify the project is clean. Use after making changes, before committing, or when the user asks to verify quality.
|
|
5
5
|
metadata:
|
|
6
6
|
author: cyanheads
|
|
7
|
-
version: "1.
|
|
7
|
+
version: "1.3"
|
|
8
8
|
audience: external
|
|
9
9
|
type: workflow
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
## What It Runs
|
|
13
13
|
|
|
14
|
-
`bun run devcheck` runs lint and
|
|
14
|
+
`bun run devcheck` runs a broader check suite than just lint + types. By default it includes local hygiene checks, MCP definition linting, Biome, TypeScript, and slow dependency/security checks unless `--fast` is passed. Tests are opt-in via `--test`.
|
|
15
15
|
|
|
16
16
|
| Check | Tool | Notes |
|
|
17
17
|
|:------|:-----|:------|
|
|
18
|
+
| TODOs / FIXMEs | `git grep` | Fails on tracked TODO/FIXME markers outside excluded files |
|
|
19
|
+
| Tracked secrets | `git ls-files` | Flags tracked `.env`, keys, credentials, and similar sensitive files |
|
|
20
|
+
| MCP definitions | `bun run scripts/lint-mcp.ts` | Validates tool/resource/prompt definitions against framework rules |
|
|
18
21
|
| Biome | `biome check` | Unified lint + format — read-only by default |
|
|
19
22
|
| TypeScript | `tsc --noEmit` | Full project type check |
|
|
23
|
+
| Unused dependencies | `depcheck` | Runs by default; network-free but slower on large repos |
|
|
24
|
+
| Security audit | `bun audit` | Runs by default unless `--fast` or `--no-audit` |
|
|
25
|
+
| Outdated dependencies | `bun outdated` | Runs by default unless `--fast` or `--no-deps` |
|
|
26
|
+
| Tests | `vitest run` | Off by default; enable with `bun run devcheck --test` |
|
|
20
27
|
|
|
21
|
-
To auto-fix lint/format issues, run `bun run format
|
|
28
|
+
To auto-fix lint/format issues, run `bun run format`.
|
|
22
29
|
|
|
23
30
|
## Steps
|
|
24
31
|
|
|
25
32
|
1. Run `bun run devcheck`
|
|
26
|
-
2. Read the
|
|
27
|
-
3. Fix
|
|
33
|
+
2. Read the failing checks in the summary and per-check output
|
|
34
|
+
3. Fix the reported issues
|
|
28
35
|
4. Re-run `bun run devcheck` until clean
|
|
29
|
-
5.
|
|
36
|
+
5. If the change touches runtime behavior, also run `bun run devcheck --test` or `bun run test`
|
|
37
|
+
6. Do not consider this skill complete until the required commands exit successfully with no errors
|
|
30
38
|
|
|
31
39
|
## Common Issues
|
|
32
40
|
|
|
33
41
|
| Check | Error Type | Typical Fix |
|
|
34
42
|
|:------|:-----------|:------------|
|
|
43
|
+
| TODOs / FIXMEs | Tracked work markers | Resolve or remove the marker before committing |
|
|
44
|
+
| Tracked secrets | Sensitive files in git | Add to `.gitignore` and remove from the index |
|
|
45
|
+
| MCP definitions | Definition lint errors | Fix schema/name/annotation issues reported by `lint-mcp` |
|
|
35
46
|
| Biome | Lint/format errors | Run `bun run format` to auto-fix, or address the flagged rule manually |
|
|
36
47
|
| TypeScript | Type errors | Fix type mismatches, missing properties, incorrect generics |
|
|
48
|
+
| Security audit | Vulnerabilities in direct deps | Update or replace the affected dependency |
|
|
49
|
+
| Outdated deps | Stale package versions | Run `bun update` or allowlist intentionally pinned packages |
|
|
37
50
|
|
|
38
51
|
## Checklist
|
|
39
52
|
|
|
40
53
|
- [ ] `bun run devcheck` exits with no errors
|
|
54
|
+
- [ ] Tests run when needed (`bun run devcheck --test` or `bun run test`)
|
|
@@ -4,14 +4,14 @@ description: >
|
|
|
4
4
|
Exercise tools, resources, and prompts with real-world inputs to verify behavior end-to-end. Use after adding or modifying definitions, or when the user asks to test, try out, or verify their MCP surface. Calls each definition with realistic and adversarial inputs and produces a report of issues, pain points, and recommendations.
|
|
5
5
|
metadata:
|
|
6
6
|
author: cyanheads
|
|
7
|
-
version: "1.
|
|
7
|
+
version: "1.1"
|
|
8
8
|
audience: external
|
|
9
9
|
type: debug
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
## Context
|
|
13
13
|
|
|
14
|
-
Unit tests (`add-test` skill) verify handler logic with mocked context. Field testing verifies the full picture: real server, real transport, real inputs, real outputs. It catches issues that unit tests miss — bad descriptions, awkward input shapes, unhelpful error messages, missing format functions, schema mismatches, and surprising edge-case behavior.
|
|
14
|
+
Unit tests (`add-test` skill) verify handler logic with mocked context. Field testing verifies the full picture: real server, real transport, real inputs, real outputs. It catches issues that unit tests miss — bad descriptions, awkward input shapes, unhelpful error messages, missing format functions, schema mismatches, silent divergence between `structuredContent` and model-visible `content[]`, and surprising edge-case behavior.
|
|
15
15
|
|
|
16
16
|
**Actively use** the tools — don't just read their code.
|
|
17
17
|
|
|
@@ -36,12 +36,17 @@ For every tool, resource, and prompt, run through these categories:
|
|
|
36
36
|
| Category | What to test |
|
|
37
37
|
|:---------|:-------------|
|
|
38
38
|
| **Happy path** | Realistic input that should succeed. Verify output shape matches the output schema. Verify format function produces sensible content blocks. |
|
|
39
|
+
| **`structuredContent` parity** | Compare the raw handler return, the data captured in `structuredContent`, and what `format()` renders into `content[]`. Flag fields or records that exist in the handler result or `structuredContent` but are absent from `content[]` unless the omission is explicit and acceptable for the tool's purpose. Most LLM clients only see `content[]`, so silent formatter drops are real bugs. |
|
|
39
40
|
| **Variations** | Different valid input combinations — optional fields omitted, optional fields included, different enum values, min/max boundaries. |
|
|
41
|
+
| **Field selection / projection** | For tools with `fields`, `include`, `expand`, `view`, or similar parameters, call the tool with non-default selections. Verify the handler returns the requested fields and `format()` renders each requested field rather than a hardcoded summary subset. |
|
|
40
42
|
| **Edge cases** | Empty strings, zero values, very long inputs, special characters, Unicode. |
|
|
41
43
|
| **Error paths** | Missing required fields, wrong types, nonexistent IDs, inputs that should trigger domain errors. Verify errors are clear and actionable — they should name what went wrong, why, and what to do next. |
|
|
42
44
|
| **Empty results** | Inputs that match nothing. Verify the response explains *why* (echoes criteria, suggests broadening) rather than returning a bare empty array. |
|
|
43
45
|
| **Partial success** | For tools that operate on multiple items, test cases where some succeed and some fail. Verify both outcomes are reported — not just the successes. |
|
|
46
|
+
| **Annotations** | Review tool `annotations` (`readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint`) against actual behavior. If a tool is marked read-only, verify it does not mutate state. If it is marked idempotent, verify retries with the same input are safe. If it is marked open-world false, verify it is not silently depending on live external systems. |
|
|
47
|
+
| **Workflow chaining** | For servers with multi-step workflows, execute 1-2 representative chains end-to-end. Example: search → detail → follow-up action. Verify each step returns the IDs, cursors, URIs, tokens, or state needed for the next step without guessing. |
|
|
44
48
|
| **Response quality** | Inspect successful responses for: (1) chaining IDs needed for follow-up calls, (2) operational metadata (counts, applied filters, truncation notices), (3) filtering transparency (if anything was excluded, does the response say what and how to include it?), (4) reasonable response size (not dumping unbounded data into context). See the `add-tool` skill's **Tool Response Design** section for the full set of patterns. |
|
|
49
|
+
| **Resilience** | For tools backed by external APIs or slow subsystems, test or explicitly note rate-limit, timeout, and transient-failure behavior. Verify retries/backoff happen where intended, or at minimum that the error message clearly tells the user whether to retry, wait, or change input. |
|
|
45
50
|
| **Descriptions** | Read every field's `.describe()` — would a user/LLM understand what to provide? Flag vague or missing descriptions. |
|
|
46
51
|
|
|
47
52
|
#### Resources
|
|
@@ -91,10 +96,15 @@ Cross-cutting observations that aren't tied to a single definition:
|
|
|
91
96
|
|
|
92
97
|
- Inconsistent error message patterns across tools
|
|
93
98
|
- Missing format functions (raw JSON returned to user)
|
|
99
|
+
- `structuredContent` contains data that `content[]` silently drops
|
|
100
|
+
- Requested projected fields are returned programmatically but not rendered for the model
|
|
94
101
|
- Description quality issues (vague, missing, or misleading)
|
|
95
102
|
- Schema design issues (required fields that should be optional, missing defaults, overly broad types, non-JSON-Schema-serializable types like `z.custom()` or `z.date()`)
|
|
103
|
+
- Annotation hints that do not match real behavior (`readOnlyHint`, `idempotentHint`, `openWorldHint`)
|
|
96
104
|
- Response quality issues (empty results with no context, silent filtering, missing chaining IDs, oversized payloads, no operational metadata)
|
|
105
|
+
- Multi-step workflows that cannot be completed because intermediate outputs omit required IDs, cursors, or URIs
|
|
97
106
|
- Error messages that don't guide recovery (generic "not found" instead of naming alternatives)
|
|
107
|
+
- Resilience issues (rate limits, timeouts, transient upstream failures handled poorly or explained poorly)
|
|
98
108
|
- Performance observations (unexpectedly slow responses)
|
|
99
109
|
|
|
100
110
|
---
|
|
@@ -106,7 +116,12 @@ Cross-cutting observations that aren't tied to a single definition:
|
|
|
106
116
|
- [ ] All registered prompts tested (happy path + defaults)
|
|
107
117
|
- [ ] Error messages reviewed for clarity and recovery guidance
|
|
108
118
|
- [ ] Empty-result responses reviewed for context (criteria echo, suggestions)
|
|
119
|
+
- [ ] `structuredContent` and `content[]` reviewed for parity
|
|
120
|
+
- [ ] Field-selection / projection behavior reviewed where applicable
|
|
109
121
|
- [ ] Response quality reviewed (chaining IDs, metadata, filtering transparency, payload size)
|
|
122
|
+
- [ ] Tool annotations reviewed against actual behavior
|
|
123
|
+
- [ ] Representative multi-step workflows exercised where applicable
|
|
124
|
+
- [ ] External API resilience reviewed where applicable (rate limits, timeouts, transient failures)
|
|
110
125
|
- [ ] Descriptions reviewed for completeness and accuracy
|
|
111
126
|
- [ ] Format functions verified (or absence noted)
|
|
112
127
|
- [ ] Summary report presented to user
|
|
@@ -4,7 +4,7 @@ description: >
|
|
|
4
4
|
Sync skills and dependencies after package updates. Use after running `bun update @cyanheads/mcp-ts-core` to ensure project skills are up to date, or periodically to check for drift.
|
|
5
5
|
metadata:
|
|
6
6
|
author: cyanheads
|
|
7
|
-
version: "1.
|
|
7
|
+
version: "1.2"
|
|
8
8
|
audience: external
|
|
9
9
|
type: workflow
|
|
10
10
|
---
|
|
@@ -35,7 +35,8 @@ After `bun update @cyanheads/mcp-ts-core`, the package may have newer skills tha
|
|
|
35
35
|
2. For any major version bumps, review changelogs before proceeding
|
|
36
36
|
3. Run `bun update` to apply updates
|
|
37
37
|
4. Run `bun audit` to check for vulnerabilities introduced by the update
|
|
38
|
-
5. Run `bun run devcheck` to confirm lint,
|
|
38
|
+
5. Run `bun run devcheck` to confirm lint, definitions, types, and dependency/security checks still pass
|
|
39
|
+
6. Run `bun run test` to confirm runtime behavior still passes
|
|
39
40
|
|
|
40
41
|
## Checklist
|
|
41
42
|
|
|
@@ -44,3 +45,4 @@ After `bun update @cyanheads/mcp-ts-core`, the package may have newer skills tha
|
|
|
44
45
|
- [ ] Dependencies updated (`bun update`)
|
|
45
46
|
- [ ] `bun audit` passes (no new vulnerabilities)
|
|
46
47
|
- [ ] `bun run devcheck` passes
|
|
48
|
+
- [ ] `bun run test` passes
|
|
@@ -4,7 +4,7 @@ description: >
|
|
|
4
4
|
Migrate an existing mcp-ts-template fork to use @cyanheads/mcp-ts-core as a package dependency. Use when a project was cloned/forked from github.com/cyanheads/mcp-ts-template and carries framework source code in its own src/ — this skill rewrites those internal imports to package subpath imports and removes the bundled framework files.
|
|
5
5
|
metadata:
|
|
6
6
|
author: cyanheads
|
|
7
|
-
version: "2.
|
|
7
|
+
version: "2.2"
|
|
8
8
|
audience: external
|
|
9
9
|
type: workflow
|
|
10
10
|
---
|
|
@@ -23,7 +23,7 @@ For the full exports catalog, see `CLAUDE.md` → Exports Reference.
|
|
|
23
23
|
2. **Search for all `@/` imports** across `src/` that reference framework internals
|
|
24
24
|
3. **Rewrite each import** using the mapping table below
|
|
25
25
|
4. **Identify framework source files** now provided by the package (see candidates below) — review each for server-specific additions before cleaning up
|
|
26
|
-
5. **Update entry point** (`src/index.ts`) to use `createApp()` from the package
|
|
26
|
+
5. **Update entry point** (`src/index.ts`) to use `createApp()` from the package and the project's chosen registration pattern (fresh scaffold default: direct imports in `src/index.ts`)
|
|
27
27
|
6. **Update build configs**:
|
|
28
28
|
- `tsconfig.json` extends `@cyanheads/mcp-ts-core/tsconfig.base.json`
|
|
29
29
|
- `biome.json` extends `@cyanheads/mcp-ts-core/biome`
|
|
@@ -113,19 +113,19 @@ Framework files within directories that contain server code:
|
|
|
113
113
|
|
|
114
114
|
## Entry point rewrite
|
|
115
115
|
|
|
116
|
-
Replace the fork's `src/index.ts` with:
|
|
116
|
+
Replace the fork's `src/index.ts` with the scaffold-default direct-registration pattern:
|
|
117
117
|
|
|
118
118
|
```ts
|
|
119
119
|
#!/usr/bin/env node
|
|
120
120
|
import { createApp } from '@cyanheads/mcp-ts-core';
|
|
121
|
-
import {
|
|
122
|
-
import {
|
|
123
|
-
import {
|
|
121
|
+
import { echoTool } from './mcp-server/tools/definitions/echo.tool.js';
|
|
122
|
+
import { echoResource } from './mcp-server/resources/definitions/echo.resource.js';
|
|
123
|
+
import { echoPrompt } from './mcp-server/prompts/definitions/echo.prompt.js';
|
|
124
124
|
|
|
125
125
|
await createApp({
|
|
126
|
-
tools:
|
|
127
|
-
resources:
|
|
128
|
-
prompts:
|
|
126
|
+
tools: [echoTool],
|
|
127
|
+
resources: [echoResource],
|
|
128
|
+
prompts: [echoPrompt],
|
|
129
129
|
});
|
|
130
130
|
```
|
|
131
131
|
|
|
@@ -133,15 +133,17 @@ Add `setup()` if the server initializes services:
|
|
|
133
133
|
|
|
134
134
|
```ts
|
|
135
135
|
await createApp({
|
|
136
|
-
tools:
|
|
137
|
-
resources:
|
|
138
|
-
prompts:
|
|
136
|
+
tools: [echoTool],
|
|
137
|
+
resources: [echoResource],
|
|
138
|
+
prompts: [echoPrompt],
|
|
139
139
|
setup(core) {
|
|
140
140
|
initMyService(core.config, core.storage);
|
|
141
141
|
},
|
|
142
142
|
});
|
|
143
143
|
```
|
|
144
144
|
|
|
145
|
+
If the migrated project already has `definitions/index.ts` barrels and you want to keep them, that is fine. The important part is removing imports from framework internals and registering definitions consistently.
|
|
146
|
+
|
|
145
147
|
## Checklist
|
|
146
148
|
|
|
147
149
|
- [ ] `@cyanheads/mcp-ts-core` installed as a dependency
|
|
@@ -4,7 +4,7 @@ description: >
|
|
|
4
4
|
Finalize documentation and project metadata for a ship-ready MCP server. Use after implementation is complete, tests pass, and devcheck is clean. Safe to run at any stage — each step checks current state and only acts on what still needs work.
|
|
5
5
|
metadata:
|
|
6
6
|
author: cyanheads
|
|
7
|
-
version: "1.
|
|
7
|
+
version: "1.3"
|
|
8
8
|
audience: external
|
|
9
9
|
type: workflow
|
|
10
10
|
---
|
|
@@ -23,7 +23,7 @@ Prefer running after implementation is complete, but safe to re-run at any point
|
|
|
23
23
|
|
|
24
24
|
- [ ] All tools/resources/prompts implemented and registered
|
|
25
25
|
- [ ] `bun run devcheck` passes
|
|
26
|
-
- [ ] Tests pass (`
|
|
26
|
+
- [ ] Tests pass (`bun run test`)
|
|
27
27
|
|
|
28
28
|
If these aren't met, address them first.
|
|
29
29
|
|
|
@@ -166,7 +166,7 @@ Run the full check suite one last time:
|
|
|
166
166
|
|
|
167
167
|
```bash
|
|
168
168
|
bun run devcheck
|
|
169
|
-
|
|
169
|
+
bun run test
|
|
170
170
|
```
|
|
171
171
|
|
|
172
172
|
Both must pass clean.
|
|
@@ -186,4 +186,4 @@ Both must pass clean.
|
|
|
186
186
|
- [ ] `Dockerfile` OCI labels and runtime config accurate (if present)
|
|
187
187
|
- [ ] `docs/tree.md` regenerated
|
|
188
188
|
- [ ] `bun run devcheck` passes
|
|
189
|
-
- [ ] `
|
|
189
|
+
- [ ] `bun run test` passes
|
package/skills/setup/SKILL.md
CHANGED
|
@@ -4,23 +4,23 @@ description: >
|
|
|
4
4
|
Post-init orientation for an MCP server built on @cyanheads/mcp-ts-core. Use after running `@cyanheads/mcp-ts-core init` to understand the project structure, conventions, and skill sync model. Also use when onboarding to an existing project for the first time.
|
|
5
5
|
metadata:
|
|
6
6
|
author: cyanheads
|
|
7
|
-
version: "1.
|
|
7
|
+
version: "1.2"
|
|
8
8
|
audience: external
|
|
9
9
|
type: workflow
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
## Context
|
|
13
13
|
|
|
14
|
-
This skill assumes `@cyanheads/mcp-ts-core init` has already run. The CLI created the project's `CLAUDE.md` and `AGENTS.md`
|
|
14
|
+
This skill assumes `@cyanheads/mcp-ts-core init` has already run. The CLI created the project's `CLAUDE.md` and `AGENTS.md` for different agents, copied external skills to `skills/`, and scaffolded the directory structure with echo definitions as starting points. This skill covers what was created and what to do next.
|
|
15
15
|
|
|
16
16
|
## Agent Protocol File
|
|
17
17
|
|
|
18
|
-
The init CLI generates both `CLAUDE.md` and `AGENTS.md` with
|
|
18
|
+
The init CLI generates both `CLAUDE.md` and `AGENTS.md` with the same purpose. Keep one authoritative file for the agent you actually use:
|
|
19
19
|
|
|
20
20
|
- **Claude Code** — keep `CLAUDE.md`, discard `AGENTS.md`
|
|
21
21
|
- **All other agents** (Codex, Cursor, Windsurf, etc.) — keep `AGENTS.md`, discard `CLAUDE.md`
|
|
22
22
|
|
|
23
|
-
Both files serve the same purpose: project-specific agent instructions.
|
|
23
|
+
Both files serve the same purpose: project-specific agent instructions. Prefer committing one authoritative copy rather than trying to keep both in sync by hand.
|
|
24
24
|
|
|
25
25
|
For the full framework API, read:
|
|
26
26
|
|
|
@@ -34,7 +34,7 @@ What `init` actually creates:
|
|
|
34
34
|
|
|
35
35
|
```text
|
|
36
36
|
CLAUDE.md # Agent protocol (project-specific)
|
|
37
|
-
AGENTS.md #
|
|
37
|
+
AGENTS.md # Alternate agent protocol file — keep the one your agent uses
|
|
38
38
|
.github/ISSUE_TEMPLATE/ # GitHub issue templates (bug report, feature request)
|
|
39
39
|
skills/ # Project skills (source of truth)
|
|
40
40
|
src/
|
|
@@ -95,19 +95,19 @@ After the initial copy, use the `maintenance` skill to keep them in sync after p
|
|
|
95
95
|
|
|
96
96
|
## Project Scaffolding
|
|
97
97
|
|
|
98
|
-
After installing dependencies (`
|
|
98
|
+
After installing dependencies (prefer `bun install`; `npm install` also works), complete these one-time setup tasks:
|
|
99
99
|
|
|
100
|
-
1. **Update dependencies to latest** — `npx npm-check-updates -u && npm install`
|
|
100
|
+
1. **Update dependencies to latest** — `bun update --latest` (or `npx npm-check-updates -u && npm install` if using npm). The scaffolded `package.json` pins minimum versions from when the framework was published; updating ensures you start with the latest compatible releases.
|
|
101
101
|
2. **Initialize git** — `git init && git add -A && git commit -m "chore: scaffold from @cyanheads/mcp-ts-core"`
|
|
102
102
|
3. **Verify agent protocol placeholders** — if the `init` CLI was run without a `[name]` argument, `{{PACKAGE_NAME}}` may remain as a literal in `CLAUDE.md`/`AGENTS.md` and `package.json`. Replace it with the actual server name.
|
|
103
103
|
|
|
104
104
|
## Checklist
|
|
105
105
|
|
|
106
|
-
- [ ] Agent protocol file selected — keep `CLAUDE.md` or `AGENTS.md
|
|
106
|
+
- [ ] Agent protocol file selected — keep one authoritative file (`CLAUDE.md` or `AGENTS.md`)
|
|
107
107
|
- [ ] `{{PACKAGE_NAME}}` placeholders replaced in agent protocol file (if not auto-substituted by init)
|
|
108
108
|
- [ ] Core framework CLAUDE.md read (`node_modules/@cyanheads/mcp-ts-core/CLAUDE.md`)
|
|
109
109
|
- [ ] Unused echo definitions cleaned up (and unregistered from `src/index.ts`)
|
|
110
110
|
- [ ] Skills copied to agent directory (`cp -R skills/* .claude/skills/` or equivalent)
|
|
111
111
|
- [ ] Project structure understood (definitions directories, entry point)
|
|
112
|
-
- [ ] `
|
|
112
|
+
- [ ] `bun run devcheck` passes
|
|
113
113
|
- [ ] If new server: proceed to `design-mcp-server` skill to plan the tool surface
|
package/templates/AGENTS.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Agent Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** {{PACKAGE_NAME}}
|
|
4
|
-
**Version:** 0.1.
|
|
4
|
+
**Version:** 0.1.1
|
|
5
5
|
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core)
|
|
6
6
|
|
|
7
7
|
> **Read the framework docs first:** `node_modules/@cyanheads/mcp-ts-core/CLAUDE.md` contains the full API reference — builders, Context, error codes, exports, patterns. This file covers server-specific conventions only.
|
|
@@ -224,6 +224,7 @@ Available skills:
|
|
|
224
224
|
| `setup` | Post-init project orientation |
|
|
225
225
|
| `design-mcp-server` | Design tool surface, resources, and services for a new server |
|
|
226
226
|
| `add-tool` | Scaffold a new tool definition |
|
|
227
|
+
| `add-app-tool` | Scaffold an MCP App tool + paired UI resource |
|
|
227
228
|
| `add-resource` | Scaffold a new resource definition |
|
|
228
229
|
| `add-prompt` | Scaffold a new prompt definition |
|
|
229
230
|
| `add-service` | Scaffold a new service integration |
|
|
@@ -281,10 +282,14 @@ import { getMyService } from '@/services/my-domain/my-service.js';
|
|
|
281
282
|
## Checklist
|
|
282
283
|
|
|
283
284
|
- [ ] Zod schemas: all fields have `.describe()`, only JSON-Schema-serializable types (no `z.custom()`, `z.date()`, `z.transform()`, etc.)
|
|
285
|
+
- [ ] Optional nested objects: handler guards for empty inner values from form-based clients (`if (input.obj?.field && ...)`, not just `if (input.obj)`)
|
|
284
286
|
- [ ] JSDoc `@fileoverview` + `@module` on every file
|
|
285
287
|
- [ ] `ctx.log` for logging, `ctx.state` for storage
|
|
286
288
|
- [ ] Handlers throw on failure — error factories or plain `Error`, no try/catch
|
|
287
289
|
- [ ] `format()` renders all data the LLM needs — `content[]` is the only field most clients forward to the model
|
|
290
|
+
- [ ] If wrapping external API: raw/domain/output schemas reviewed against real upstream sparsity/nullability before finalizing required vs optional fields
|
|
291
|
+
- [ ] If wrapping external API: normalization and `format()` preserve uncertainty; do not fabricate facts from missing upstream data
|
|
292
|
+
- [ ] If wrapping external API: tests include at least one sparse payload case with omitted upstream fields
|
|
288
293
|
- [ ] Registered in `createApp()` arrays (directly or via barrel exports)
|
|
289
294
|
- [ ] Tests use `createMockContext()` from `@cyanheads/mcp-ts-core/testing`
|
|
290
295
|
- [ ] `npm run devcheck` passes
|
package/templates/CLAUDE.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Agent Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** {{PACKAGE_NAME}}
|
|
4
|
-
**Version:** 0.1.
|
|
4
|
+
**Version:** 0.1.1
|
|
5
5
|
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core)
|
|
6
6
|
|
|
7
7
|
> **Read the framework docs first:** `node_modules/@cyanheads/mcp-ts-core/CLAUDE.md` contains the full API reference — builders, Context, error codes, exports, patterns. This file covers server-specific conventions only.
|
|
@@ -25,7 +25,7 @@ When the user asks what to do next, what's left, or needs direction, suggest rel
|
|
|
25
25
|
|
|
26
26
|
1. **Re-run the `setup` skill** — ensures CLAUDE.md, skills, structure, and metadata are populated and up to date with the current codebase
|
|
27
27
|
2. **Run the `design-mcp-server` skill** — if the tool/resource surface hasn't been mapped yet, work through domain design
|
|
28
|
-
3. **Add tools/resources/prompts** — scaffold new definitions using the `add-tool`, `add-resource`, `add-prompt` skills
|
|
28
|
+
3. **Add tools/resources/prompts** — scaffold new definitions using the `add-tool`, `add-app-tool`, `add-resource`, `add-prompt` skills
|
|
29
29
|
4. **Add services** — scaffold domain service integrations using the `add-service` skill
|
|
30
30
|
5. **Add tests** — scaffold tests for existing definitions using the `add-test` skill
|
|
31
31
|
6. **Field-test definitions** — exercise tools/resources/prompts with real inputs using the `field-test` skill, get a report of issues and pain points
|
|
@@ -224,6 +224,7 @@ Available skills:
|
|
|
224
224
|
| `setup` | Post-init project orientation |
|
|
225
225
|
| `design-mcp-server` | Design tool surface, resources, and services for a new server |
|
|
226
226
|
| `add-tool` | Scaffold a new tool definition |
|
|
227
|
+
| `add-app-tool` | Scaffold an MCP App tool + paired UI resource |
|
|
227
228
|
| `add-resource` | Scaffold a new resource definition |
|
|
228
229
|
| `add-prompt` | Scaffold a new prompt definition |
|
|
229
230
|
| `add-service` | Scaffold a new service integration |
|
|
@@ -286,6 +287,9 @@ import { getMyService } from '@/services/my-domain/my-service.js';
|
|
|
286
287
|
- [ ] `ctx.log` for logging, `ctx.state` for storage
|
|
287
288
|
- [ ] Handlers throw on failure — error factories or plain `Error`, no try/catch
|
|
288
289
|
- [ ] `format()` renders all data the LLM needs — `content[]` is the only field most clients forward to the model
|
|
290
|
+
- [ ] If wrapping external API: raw/domain/output schemas reviewed against real upstream sparsity/nullability before finalizing required vs optional fields
|
|
291
|
+
- [ ] If wrapping external API: normalization and `format()` preserve uncertainty; do not fabricate facts from missing upstream data
|
|
292
|
+
- [ ] If wrapping external API: tests include at least one sparse payload case with omitted upstream fields
|
|
289
293
|
- [ ] Registered in `createApp()` arrays (directly or via barrel exports)
|
|
290
294
|
- [ ] Tests use `createMockContext()` from `@cyanheads/mcp-ts-core/testing`
|
|
291
295
|
- [ ] `npm run devcheck` passes
|
|
@@ -62,7 +62,12 @@ const APP_HTML = `<!DOCTYPE html>
|
|
|
62
62
|
</div>
|
|
63
63
|
|
|
64
64
|
<script type="module">
|
|
65
|
-
import {
|
|
65
|
+
import {
|
|
66
|
+
App,
|
|
67
|
+
applyDocumentTheme,
|
|
68
|
+
applyHostFonts,
|
|
69
|
+
applyHostStyleVariables,
|
|
70
|
+
} from "https://unpkg.com/@modelcontextprotocol/ext-apps@1/app-with-deps";
|
|
66
71
|
|
|
67
72
|
const app = new App({ name: "Echo App", version: "1.0.0" });
|
|
68
73
|
const messageEl = document.getElementById("message");
|
|
@@ -70,6 +75,18 @@ const APP_HTML = `<!DOCTYPE html>
|
|
|
70
75
|
const inputEl = document.getElementById("input");
|
|
71
76
|
const sendBtn = document.getElementById("send");
|
|
72
77
|
|
|
78
|
+
function applyHostContext(hostContext) {
|
|
79
|
+
if (hostContext?.theme) {
|
|
80
|
+
applyDocumentTheme(hostContext.theme);
|
|
81
|
+
}
|
|
82
|
+
if (hostContext?.styles?.variables) {
|
|
83
|
+
applyHostStyleVariables(hostContext.styles.variables);
|
|
84
|
+
}
|
|
85
|
+
if (hostContext?.styles?.css?.fonts) {
|
|
86
|
+
applyHostFonts(hostContext.styles.css.fonts);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
73
90
|
function render(content) {
|
|
74
91
|
const text = content?.find(c => c.type === "text")?.text;
|
|
75
92
|
if (!text) return;
|
|
@@ -82,6 +99,7 @@ const APP_HTML = `<!DOCTYPE html>
|
|
|
82
99
|
|
|
83
100
|
// Receive initial tool result pushed by the host
|
|
84
101
|
app.ontoolresult = (result) => render(result.content);
|
|
102
|
+
app.onhostcontextchanged = applyHostContext;
|
|
85
103
|
|
|
86
104
|
// Send new echo from the UI
|
|
87
105
|
sendBtn.addEventListener("click", async () => {
|
|
@@ -106,7 +124,10 @@ const APP_HTML = `<!DOCTYPE html>
|
|
|
106
124
|
if (e.key === "Enter") sendBtn.click();
|
|
107
125
|
});
|
|
108
126
|
|
|
109
|
-
|
|
127
|
+
app.connect().then(() => {
|
|
128
|
+
const hostContext = app.getHostContext();
|
|
129
|
+
if (hostContext) applyHostContext(hostContext);
|
|
130
|
+
});
|
|
110
131
|
</script>
|
|
111
132
|
</body>
|
|
112
133
|
</html>`;
|
|
@@ -119,13 +140,13 @@ export const echoAppUiResource = appResource('ui://template-echo-app/app.html',
|
|
|
119
140
|
description:
|
|
120
141
|
'Interactive HTML app for the echo app tool. Displayed as a sandboxed iframe ' +
|
|
121
142
|
'by MCP Apps-capable hosts.',
|
|
143
|
+
params: ParamsSchema,
|
|
144
|
+
auth: ['resource:echo-app-ui:read'],
|
|
122
145
|
_meta: {
|
|
123
146
|
ui: {
|
|
124
147
|
csp: { resourceDomains: ['https://unpkg.com'] },
|
|
125
148
|
},
|
|
126
149
|
},
|
|
127
|
-
params: ParamsSchema,
|
|
128
|
-
auth: ['resource:echo-app-ui:read'],
|
|
129
150
|
|
|
130
151
|
handler(_params, ctx) {
|
|
131
152
|
ctx.log.debug('Serving echo app UI.', { resourceUri: ctx.uri?.href });
|