@cyanheads/mcp-ts-core 0.4.1 → 0.5.2
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 +30 -33
- package/README.md +6 -7
- package/dist/config/index.d.ts +1 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +1 -0
- package/dist/config/index.js.map +1 -1
- package/dist/config/parseEnvConfig.d.ts +48 -0
- package/dist/config/parseEnvConfig.d.ts.map +1 -0
- package/dist/config/parseEnvConfig.js +73 -0
- package/dist/config/parseEnvConfig.js.map +1 -0
- package/dist/core/app.d.ts.map +1 -1
- package/dist/core/app.js +65 -3
- package/dist/core/app.js.map +1 -1
- package/dist/linter/rules/format-parity-rules.d.ts +34 -0
- package/dist/linter/rules/format-parity-rules.d.ts.map +1 -0
- package/dist/linter/rules/format-parity-rules.js +335 -0
- package/dist/linter/rules/format-parity-rules.js.map +1 -0
- package/dist/linter/rules/tool-rules.d.ts.map +1 -1
- package/dist/linter/rules/tool-rules.js +5 -0
- package/dist/linter/rules/tool-rules.js.map +1 -1
- package/package.json +10 -15
- package/skills/add-tool/SKILL.md +3 -2
- package/skills/api-config/SKILL.md +17 -5
- package/skills/field-test/SKILL.md +2 -2
- package/skills/maintenance/SKILL.md +141 -22
- package/skills/polish-docs-meta/SKILL.md +2 -2
- package/skills/polish-docs-meta/references/readme.md +217 -79
- package/skills/setup/SKILL.md +3 -3
- package/templates/AGENTS.md +19 -11
- package/templates/CLAUDE.md +18 -10
- package/skills/devcheck/SKILL.md +0 -54
- package/skills/walkthrough-init/SKILL.md +0 -50
|
@@ -7,42 +7,47 @@ Structure and content guide for creating or updating a README for an MCP server
|
|
|
7
7
|
Use this section order. Omit sections that don't apply (e.g., skip Docker/Workers if the server doesn't deploy there).
|
|
8
8
|
|
|
9
9
|
```text
|
|
10
|
-
# {Server Name}
|
|
11
|
-
|
|
10
|
+
# {Server Name} ← centered HTML block
|
|
11
|
+
[Public hosted callout if present] ← centered HTML block, directly under badges
|
|
12
|
+
Badges row ← npm, Docker, Version, Framework, MCP SDK, License, TS, Bun, Coverage
|
|
12
13
|
---
|
|
13
|
-
## Tools
|
|
14
|
-
## Resources (if any)
|
|
15
|
-
##
|
|
16
|
-
##
|
|
17
|
-
##
|
|
18
|
-
##
|
|
19
|
-
##
|
|
20
|
-
##
|
|
21
|
-
##
|
|
22
|
-
##
|
|
23
|
-
## License ← one line
|
|
14
|
+
## Tools ← grouping sentence → summary table → per-tool subsections
|
|
15
|
+
## Resources and prompts (if any) ← single combined table (Type / Name / Description)
|
|
16
|
+
## Features ← framework bullets + domain-specific bullets
|
|
17
|
+
## Getting started ← hosted (if any), bunx/npx/docker configs, HTTP one-liner, prerequisites, install
|
|
18
|
+
## Configuration ← env var table + `.env.example` pointer
|
|
19
|
+
## Running the server ← dev, production, Workers/Docker
|
|
20
|
+
## Project structure ← directory/purpose table
|
|
21
|
+
## Development guide ← link to CLAUDE.md, key rules
|
|
22
|
+
## Contributing ← brief
|
|
23
|
+
## License ← one line
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
## Section Guide
|
|
27
27
|
|
|
28
28
|
### Title Block
|
|
29
29
|
|
|
30
|
-
Centered HTML. The `<h1>` is the server name — use the scoped package name if published under a scope (e.g., `@cyanheads/my-mcp-server`). The `<p>` is a bold one-liner: what the server wraps, key capabilities, transport/deployment options.
|
|
30
|
+
Centered HTML. The `<h1>` is the server name — use the scoped package name if published under a scope (e.g., `@cyanheads/my-mcp-server`). The `<p>` is a bold one-liner: what the server wraps, key capabilities, transport/deployment options. **Nest the surface count as a `<div>` inside the same `<p>`**, separated by `•` (U+2022 bullet) — not as a second `<p>`. This matches the shipping convention across `@cyanheads/*` servers.
|
|
31
31
|
|
|
32
32
|
```html
|
|
33
33
|
<div align="center">
|
|
34
34
|
<h1>@cyanheads/my-mcp-server</h1>
|
|
35
|
-
<p><b>MCP server for the Acme API
|
|
36
|
-
<
|
|
35
|
+
<p><b>MCP server for the Acme API — search projects, manage tasks, track teams. STDIO or Streamable HTTP.</b>
|
|
36
|
+
<div>7 Tools • 2 Resources • 1 Prompt</div>
|
|
37
|
+
</p>
|
|
37
38
|
</div>
|
|
38
39
|
|
|
39
40
|
<div align="center">
|
|
40
41
|
|
|
41
|
-
[](https://www.npmjs.com/package/my-mcp-server) [](./CHANGELOG.md) [](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) [](https://www.npmjs.com/package/@cyanheads/my-mcp-server) [](./CHANGELOG.md) [](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) [](https://modelcontextprotocol.io/)
|
|
43
|
+
|
|
44
|
+
[](./LICENSE) [](https://www.typescriptlang.org/) [](https://bun.sh/)
|
|
42
45
|
|
|
43
46
|
</div>
|
|
44
47
|
```
|
|
45
48
|
|
|
49
|
+
The header tagline must match the `package.json` `description`.
|
|
50
|
+
|
|
46
51
|
**Badge selection:** All badges use `style=flat-square`. Include what applies — don't add badges for things the server doesn't have:
|
|
47
52
|
|
|
48
53
|
| Badge | When to include |
|
|
@@ -51,19 +56,41 @@ Centered HTML. The `<h1>` is the server name — use the scoped package name if
|
|
|
51
56
|
| Docker | Published to ghcr.io or Docker Hub |
|
|
52
57
|
| Version | Always — link to CHANGELOG.md |
|
|
53
58
|
| Framework | Always — links to `@cyanheads/mcp-ts-core` on npm |
|
|
54
|
-
| MCP Spec | Always — link to the spec version implemented |
|
|
55
59
|
| MCP SDK | Always — show the `@modelcontextprotocol/sdk` version |
|
|
56
60
|
| License | Always |
|
|
57
|
-
| Status | Optional — Stable, Beta, etc. |
|
|
58
61
|
| TypeScript | Always |
|
|
59
|
-
| Bun | If using Bun |
|
|
62
|
+
| Bun | If using Bun (standard for this framework) |
|
|
63
|
+
| MCP Spec | Optional — rarely included; the SDK badge usually suffices |
|
|
64
|
+
| Status | Optional — Stable, Beta, etc. |
|
|
60
65
|
| Code Coverage | If coverage is tracked |
|
|
61
66
|
|
|
62
67
|
Add a `---` horizontal rule after the badge block.
|
|
63
68
|
|
|
69
|
+
### Public Hosted Callout (if present)
|
|
70
|
+
|
|
71
|
+
If a public hosted instance is available, **promote it to a top-level callout** immediately below the badge block — don't bury it inside Getting Started. This is the highest-value piece of information for a visitor who wants to try the server with zero install.
|
|
72
|
+
|
|
73
|
+
```html
|
|
74
|
+
<div align="center">
|
|
75
|
+
|
|
76
|
+
**Public Hosted Server:** [https://my-server.example.com/mcp](https://my-server.example.com/mcp)
|
|
77
|
+
|
|
78
|
+
</div>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Keep the full connection-config JSON block inside a `### Public Hosted Instance` subsection under Getting Started (covered below). This callout is just the visibility pointer.
|
|
82
|
+
|
|
64
83
|
### Tools
|
|
65
84
|
|
|
66
|
-
This is the most important section — it tells humans and LLMs exactly what the server exposes.
|
|
85
|
+
This is the most important section — it tells humans and LLMs exactly what the server exposes. Three layers: a **grouping framing sentence**, a summary table, then per-tool subsections for tools with non-trivial behavior.
|
|
86
|
+
|
|
87
|
+
**Grouping framing sentence:** Lead with one sentence that explains how the tool surface is organized. Richer than a bare count — tells the reader what mental model to apply. Examples:
|
|
88
|
+
|
|
89
|
+
- "Seventeen tools grouped by shape — workflow helpers orchestrate common flows end-to-end, primitive tools expose fine-grained CRUD, and the instruction tool returns procedural guidance merged with live account state."
|
|
90
|
+
- "Nine tools for working with PubMed and NCBI data:"
|
|
91
|
+
- "Five tools covering project lifecycle — discovery, task CRUD, and team analytics."
|
|
92
|
+
|
|
93
|
+
If the tools aren't meaningfully grouped, a single sentence count ("Seven tools for working with Acme data:") is acceptable.
|
|
67
94
|
|
|
68
95
|
**Summary table:**
|
|
69
96
|
|
|
@@ -79,8 +106,6 @@ Seven tools for working with Acme data:
|
|
|
79
106
|
| `get_task` | Fetch one or more tasks by ID, with full or summary data. |
|
|
80
107
|
```
|
|
81
108
|
|
|
82
|
-
Lead with a one-line count: "Seven tools for working with X data:" (or "Three tools", etc.).
|
|
83
|
-
|
|
84
109
|
**Per-tool subsections:**
|
|
85
110
|
|
|
86
111
|
Below the table, add a `### tool_name` subsection for each tool that has meaningful detail beyond its one-line description. Include:
|
|
@@ -110,34 +135,35 @@ Fetch one or more tasks by ID, with full data or concise summaries.
|
|
|
110
135
|
- Batch fetch up to 5 tasks at once
|
|
111
136
|
- Full data includes subtasks, comments, attachments, and history
|
|
112
137
|
- Partial success reporting when some tasks in a batch fail
|
|
113
|
-
|
|
114
|
-
[View detailed examples](./examples/get_task.md)
|
|
115
138
|
```
|
|
116
139
|
|
|
117
140
|
Skip the per-tool subsection for simple tools where the table description says everything (e.g., a `get_field_values` lookup tool).
|
|
118
141
|
|
|
119
|
-
### Resources (
|
|
142
|
+
### Resources and Prompts (combined)
|
|
143
|
+
|
|
144
|
+
**Use a single combined table with a `Type` column** rather than separate `## Resources` and `## Prompts` sections. This is the shipping convention — it scales better when a server has only 1 or 2 of each, and co-locates related content.
|
|
120
145
|
|
|
121
146
|
```markdown
|
|
122
|
-
## Resources
|
|
147
|
+
## Resources and prompts
|
|
123
148
|
|
|
124
|
-
|
|
|
125
|
-
|
|
126
|
-
| `acme://projects/{projectId}` | Project details by ID |
|
|
127
|
-
| `acme://tasks/{taskId}` | Task details by ID |
|
|
149
|
+
| Type | Name | Description |
|
|
150
|
+
|:---|:---|:---|
|
|
151
|
+
| Resource | `acme://projects/{projectId}` | Project details by ID |
|
|
152
|
+
| Resource | `acme://tasks/{taskId}` | Task details by ID |
|
|
153
|
+
| Prompt | `project_summary` | Summarize a project's status and open tasks |
|
|
128
154
|
```
|
|
129
155
|
|
|
130
|
-
|
|
156
|
+
Use singular ("Resource and prompt") if there's only one of each.
|
|
131
157
|
|
|
132
|
-
|
|
133
|
-
## Prompts
|
|
158
|
+
**Always include the tool-coverage note** directly under the table. Many MCP clients are tool-only and don't surface resources — this tells both the reader and downstream agents that the data is still reachable:
|
|
134
159
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
| `project_summary` | Summarize a project's status and open tasks |
|
|
160
|
+
```markdown
|
|
161
|
+
All resource data is also reachable via tools. Large collections (`projects`, `tasks`) are not exposed as resources — use the `list` operation on the corresponding tool instead.
|
|
138
162
|
```
|
|
139
163
|
|
|
140
|
-
|
|
164
|
+
If a prompt has an associated design doc or reference, link it in the same paragraph: `Design reference for the prompt: [\`docs/email-design-playbook.md\`](./docs/email-design-playbook.md).`
|
|
165
|
+
|
|
166
|
+
Derive all tool/resource/prompt rows directly from the actual definitions. Use the real names and descriptions from the Zod schemas.
|
|
141
167
|
|
|
142
168
|
### Features
|
|
143
169
|
|
|
@@ -146,90 +172,166 @@ Two subsection groups: framework capabilities, then domain-specific capabilities
|
|
|
146
172
|
```markdown
|
|
147
173
|
## Features
|
|
148
174
|
|
|
149
|
-
Built on [`@cyanheads/mcp-ts-core`](https://
|
|
175
|
+
Built on [`@cyanheads/mcp-ts-core`](https://www.npmjs.com/package/@cyanheads/mcp-ts-core):
|
|
150
176
|
|
|
151
|
-
- Declarative tool definitions — single file per
|
|
152
|
-
- Unified error handling
|
|
153
|
-
- Pluggable auth
|
|
177
|
+
- Declarative tool, resource, and prompt definitions — single file per primitive, framework handles registration and validation
|
|
178
|
+
- Unified error handling — handlers throw, framework catches, classifies, and formats
|
|
179
|
+
- Pluggable auth: `none`, `jwt`, `oauth`
|
|
154
180
|
- Swappable storage backends: `in-memory`, `filesystem`, `Supabase`, `Cloudflare KV/R2/D1`
|
|
155
181
|
- Structured logging with optional OpenTelemetry tracing
|
|
156
|
-
-
|
|
182
|
+
- STDIO and Streamable HTTP transports
|
|
157
183
|
|
|
158
184
|
Acme-specific:
|
|
159
185
|
|
|
160
186
|
- Type-safe client for the Acme v2 API
|
|
161
187
|
- Automatic cleaning and simplification of API responses for agent consumption
|
|
188
|
+
- Workflow tools parallelize related sub-requests under a configurable concurrency limit
|
|
162
189
|
```
|
|
163
190
|
|
|
164
191
|
### Getting Started
|
|
165
192
|
|
|
166
|
-
Lead with the lowest-friction option. If a public hosted instance exists, show that first. Then
|
|
193
|
+
Lead with the lowest-friction option. If a public hosted instance exists, show that first. Then the **three standard install configs in order — `bunx`, `npx`, `docker run`** — followed by the HTTP one-liner quickstart, then prerequisites and install steps.
|
|
167
194
|
|
|
168
|
-
|
|
169
|
-
## Getting Started
|
|
195
|
+
**Standard three-block pattern** (the house style across shipping `@cyanheads/*` servers):
|
|
170
196
|
|
|
171
|
-
|
|
197
|
+
```markdown
|
|
198
|
+
## Getting started
|
|
172
199
|
|
|
173
|
-
|
|
200
|
+
Add the following to your MCP client configuration file. See [`docs/api-key.md`](./docs/api-key.md) for how to generate an API key.
|
|
174
201
|
|
|
175
202
|
\`\`\`json
|
|
176
203
|
{
|
|
177
204
|
"mcpServers": {
|
|
178
205
|
"my-server": {
|
|
179
|
-
"type": "
|
|
180
|
-
"
|
|
206
|
+
"type": "stdio",
|
|
207
|
+
"command": "bunx",
|
|
208
|
+
"args": ["@cyanheads/my-mcp-server@latest"],
|
|
209
|
+
"env": {
|
|
210
|
+
"MCP_TRANSPORT_TYPE": "stdio",
|
|
211
|
+
"MCP_LOG_LEVEL": "info",
|
|
212
|
+
"ACME_API_KEY": "your-api-key"
|
|
213
|
+
}
|
|
181
214
|
}
|
|
182
215
|
}
|
|
183
216
|
}
|
|
184
217
|
\`\`\`
|
|
185
218
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
Add to your MCP client config (e.g., `claude_desktop_config.json`):
|
|
219
|
+
Or with npx (no Bun required):
|
|
189
220
|
|
|
190
221
|
\`\`\`json
|
|
191
222
|
{
|
|
192
223
|
"mcpServers": {
|
|
193
|
-
"my-
|
|
224
|
+
"my-server": {
|
|
194
225
|
"type": "stdio",
|
|
195
|
-
"command": "
|
|
196
|
-
"args": ["my-mcp-server@latest"],
|
|
226
|
+
"command": "npx",
|
|
227
|
+
"args": ["-y", "@cyanheads/my-mcp-server@latest"],
|
|
197
228
|
"env": {
|
|
198
|
-
"
|
|
199
|
-
"
|
|
229
|
+
"MCP_TRANSPORT_TYPE": "stdio",
|
|
230
|
+
"MCP_LOG_LEVEL": "info",
|
|
231
|
+
"ACME_API_KEY": "your-api-key"
|
|
200
232
|
}
|
|
201
233
|
}
|
|
202
234
|
}
|
|
203
235
|
}
|
|
204
236
|
\`\`\`
|
|
205
237
|
|
|
238
|
+
Or with Docker:
|
|
239
|
+
|
|
240
|
+
\`\`\`json
|
|
241
|
+
{
|
|
242
|
+
"mcpServers": {
|
|
243
|
+
"my-server": {
|
|
244
|
+
"type": "stdio",
|
|
245
|
+
"command": "docker",
|
|
246
|
+
"args": [
|
|
247
|
+
"run", "-i", "--rm",
|
|
248
|
+
"-e", "MCP_TRANSPORT_TYPE=stdio",
|
|
249
|
+
"-e", "ACME_API_KEY=your-api-key",
|
|
250
|
+
"ghcr.io/cyanheads/my-mcp-server:latest"
|
|
251
|
+
]
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
\`\`\`
|
|
256
|
+
|
|
257
|
+
For Streamable HTTP, set the transport and start the server:
|
|
258
|
+
|
|
259
|
+
\`\`\`sh
|
|
260
|
+
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 ACME_API_KEY=... bun run start:http
|
|
261
|
+
# Server listens at http://localhost:3010/mcp
|
|
262
|
+
\`\`\`
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Refer to "your MCP client configuration file" generically — don't prescribe `claude_desktop_config.json` by name. Different clients use different config paths and the server isn't client-specific.
|
|
266
|
+
|
|
267
|
+
**If a public hosted instance exists**, precede the three-block pattern with a `### Public Hosted Instance` subsection and wrap the local configs in a `### Self-Hosted / Local` subsection:
|
|
268
|
+
|
|
269
|
+
```markdown
|
|
270
|
+
### Public Hosted Instance
|
|
271
|
+
|
|
272
|
+
A public instance is available at `https://my-server.example.com/mcp` — no installation required. Point any MCP client at it via Streamable HTTP:
|
|
273
|
+
|
|
274
|
+
\`\`\`json
|
|
275
|
+
{
|
|
276
|
+
"mcpServers": {
|
|
277
|
+
"my-server": {
|
|
278
|
+
"type": "streamable-http",
|
|
279
|
+
"url": "https://my-server.example.com/mcp"
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
\`\`\`
|
|
284
|
+
|
|
285
|
+
### Self-Hosted / Local
|
|
286
|
+
|
|
287
|
+
[bunx / npx / docker blocks here]
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
**Prerequisites:** Include a Bun version line and any domain-specific setup (API key format, rate-limit tiers, required accounts). Don't just list Bun — readers need to know what else to prepare.
|
|
291
|
+
|
|
292
|
+
```markdown
|
|
206
293
|
### Prerequisites
|
|
207
294
|
|
|
208
|
-
- [Bun v1.2
|
|
295
|
+
- [Bun v1.3.2](https://bun.sh/) or higher (or Node.js v22+).
|
|
296
|
+
- An Acme API key — see [`docs/api-key.md`](./docs/api-key.md) for how to generate one.
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**Installation:** Standard four steps (clone, cd, install, configure env):
|
|
209
300
|
|
|
301
|
+
```markdown
|
|
210
302
|
### Installation
|
|
211
303
|
|
|
212
304
|
1. **Clone the repository:**
|
|
305
|
+
|
|
213
306
|
\`\`\`sh
|
|
214
307
|
git clone https://github.com/cyanheads/my-mcp-server.git
|
|
215
308
|
\`\`\`
|
|
216
309
|
|
|
217
310
|
2. **Navigate into the directory:**
|
|
311
|
+
|
|
218
312
|
\`\`\`sh
|
|
219
313
|
cd my-mcp-server
|
|
220
314
|
\`\`\`
|
|
221
315
|
|
|
222
316
|
3. **Install dependencies:**
|
|
317
|
+
|
|
223
318
|
\`\`\`sh
|
|
224
319
|
bun install
|
|
225
320
|
\`\`\`
|
|
321
|
+
|
|
322
|
+
4. **Configure environment:**
|
|
323
|
+
|
|
324
|
+
\`\`\`sh
|
|
325
|
+
cp .env.example .env
|
|
326
|
+
# edit .env and set required vars
|
|
327
|
+
\`\`\`
|
|
226
328
|
```
|
|
227
329
|
|
|
228
|
-
Omit the
|
|
330
|
+
Omit the clone/install steps if the server is npm-only (not meant to be cloned).
|
|
229
331
|
|
|
230
332
|
### Configuration
|
|
231
333
|
|
|
232
|
-
Table of environment variables. Include framework vars only if the server uses non-default values.
|
|
334
|
+
Table of environment variables. Include framework vars only if the server uses non-default values. Mark required vars with bold **Required.** in the description rather than a separate column. **Close with a pointer to `.env.example`** for the full list of optional overrides.
|
|
233
335
|
|
|
234
336
|
```markdown
|
|
235
337
|
## Configuration
|
|
@@ -238,6 +340,7 @@ Table of environment variables. Include framework vars only if the server uses n
|
|
|
238
340
|
|:---------|:------------|:--------|
|
|
239
341
|
| `ACME_API_KEY` | **Required.** API key for the Acme service. | — |
|
|
240
342
|
| `ACME_BASE_URL` | API base URL. | `https://api.acme.com` |
|
|
343
|
+
| `ACME_TIMEOUT_MS` | Per-request timeout in milliseconds. | `60000` |
|
|
241
344
|
| `MCP_TRANSPORT_TYPE` | Transport: `stdio` or `http`. | `stdio` |
|
|
242
345
|
| `MCP_HTTP_PORT` | Port for HTTP server. | `3010` |
|
|
243
346
|
| `MCP_AUTH_MODE` | Auth mode: `none`, `jwt`, or `oauth`. | `none` |
|
|
@@ -245,74 +348,105 @@ Table of environment variables. Include framework vars only if the server uses n
|
|
|
245
348
|
| `LOGS_DIR` | Directory for log files (Node.js only). | `<project-root>/logs` |
|
|
246
349
|
| `STORAGE_PROVIDER_TYPE` | Storage backend. | `in-memory` |
|
|
247
350
|
| `OTEL_ENABLED` | Enable OpenTelemetry. | `false` |
|
|
351
|
+
|
|
352
|
+
See [`.env.example`](./.env.example) for the full list of optional overrides.
|
|
248
353
|
```
|
|
249
354
|
|
|
250
|
-
Source from the server config Zod schema and `.env.example`.
|
|
355
|
+
Source from the server config Zod schema and `.env.example`.
|
|
251
356
|
|
|
252
357
|
### Running the Server
|
|
253
358
|
|
|
254
|
-
Separate from Getting Started. Show build + run
|
|
359
|
+
Separate from Getting Started. Show dev, build + run, and Workers/Docker deployment if applicable.
|
|
255
360
|
|
|
256
361
|
```markdown
|
|
257
|
-
## Running the
|
|
362
|
+
## Running the server
|
|
363
|
+
|
|
364
|
+
### Local development
|
|
258
365
|
|
|
259
|
-
|
|
366
|
+
- **Hot-reload dev mode:**
|
|
367
|
+
|
|
368
|
+
\`\`\`sh
|
|
369
|
+
bun run dev:stdio
|
|
370
|
+
bun run dev:http
|
|
371
|
+
\`\`\`
|
|
260
372
|
|
|
261
373
|
- **Build and run the production version:**
|
|
374
|
+
|
|
262
375
|
\`\`\`sh
|
|
263
|
-
|
|
264
|
-
bun run
|
|
376
|
+
# One-time build
|
|
377
|
+
bun run rebuild
|
|
378
|
+
|
|
379
|
+
# Run the built server
|
|
380
|
+
bun run start:stdio
|
|
381
|
+
# or
|
|
382
|
+
bun run start:http
|
|
265
383
|
\`\`\`
|
|
266
384
|
|
|
267
385
|
- **Run checks and tests:**
|
|
386
|
+
|
|
268
387
|
\`\`\`sh
|
|
269
|
-
bun run devcheck
|
|
270
|
-
bun run test
|
|
388
|
+
bun run devcheck # Lint, format, typecheck, security
|
|
389
|
+
bun run test # Vitest test suite
|
|
390
|
+
bun run lint:mcp # Validate MCP definitions against spec
|
|
271
391
|
\`\`\`
|
|
272
392
|
|
|
393
|
+
### Docker
|
|
394
|
+
|
|
395
|
+
\`\`\`sh
|
|
396
|
+
docker build -t my-mcp-server .
|
|
397
|
+
docker run --rm -e ACME_API_KEY=your-key -p 3010:3010 my-mcp-server
|
|
398
|
+
\`\`\`
|
|
399
|
+
|
|
400
|
+
The Dockerfile defaults to HTTP transport, stateless session mode, and logs to `/var/log/my-mcp-server`. OpenTelemetry peer dependencies are installed by default — build with `--build-arg OTEL_ENABLED=false` to omit them.
|
|
401
|
+
|
|
273
402
|
### Cloudflare Workers
|
|
274
403
|
|
|
275
404
|
1. **Build the Worker bundle:**
|
|
405
|
+
|
|
276
406
|
\`\`\`sh
|
|
277
407
|
bun run build:worker
|
|
278
408
|
\`\`\`
|
|
279
409
|
|
|
280
410
|
2. **Deploy:**
|
|
411
|
+
|
|
281
412
|
\`\`\`sh
|
|
282
413
|
bun run deploy:prod
|
|
283
414
|
\`\`\`
|
|
284
415
|
```
|
|
285
416
|
|
|
286
|
-
Include the Docker or Workers subsection only if the server supports it.
|
|
417
|
+
Include the Docker or Workers subsection only if the server supports it. The Docker trailing paragraph (log directory, OTEL build arg) is important — it documents Dockerfile behavior that isn't obvious from the build command.
|
|
287
418
|
|
|
288
419
|
### Project Structure
|
|
289
420
|
|
|
290
421
|
Directory/purpose table orienting contributors to the codebase.
|
|
291
422
|
|
|
292
423
|
```markdown
|
|
293
|
-
## Project
|
|
424
|
+
## Project structure
|
|
294
425
|
|
|
295
426
|
| Directory | Purpose |
|
|
296
427
|
|:----------|:--------|
|
|
428
|
+
| `src/index.ts` | `createApp()` entry point — registers tools/resources/prompts and inits services. |
|
|
429
|
+
| `src/config` | Server-specific environment variable parsing and validation with Zod. |
|
|
297
430
|
| `src/mcp-server/tools` | Tool definitions (`*.tool.ts`). |
|
|
298
431
|
| `src/mcp-server/resources` | Resource definitions (`*.resource.ts`). |
|
|
432
|
+
| `src/mcp-server/prompts` | Prompt definitions (`*.prompt.ts`). |
|
|
299
433
|
| `src/services` | Domain service integrations. |
|
|
300
|
-
| `src/config` | Environment variable parsing and validation with Zod. |
|
|
301
434
|
| `tests/` | Unit and integration tests mirroring `src/`. |
|
|
302
435
|
```
|
|
303
436
|
|
|
304
437
|
### Development Guide
|
|
305
438
|
|
|
306
|
-
Brief — link to CLAUDE.md for full details. State
|
|
439
|
+
Brief — link to CLAUDE.md for full details. State 3-4 key rules. **Include the "validate → normalize → never fabricate" bullet** — it's the canonical anti-hallucination convention for external API wrappers and reinforces the framework's `no fabricated signal` principle.
|
|
307
440
|
|
|
308
441
|
```markdown
|
|
309
|
-
## Development
|
|
442
|
+
## Development guide
|
|
310
443
|
|
|
311
444
|
See [`CLAUDE.md`](./CLAUDE.md) for development guidelines and architectural rules. The short version:
|
|
312
445
|
|
|
313
446
|
- Handlers throw, framework catches — no `try/catch` in tool logic
|
|
314
|
-
- Use `ctx.log` for
|
|
315
|
-
- Register new tools and resources
|
|
447
|
+
- Use `ctx.log` for request-scoped logging, `ctx.state` for tenant-scoped storage
|
|
448
|
+
- Register new tools and resources via the barrels in `src/mcp-server/*/definitions/index.ts`
|
|
449
|
+
- Wrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields
|
|
316
450
|
```
|
|
317
451
|
|
|
318
452
|
### Contributing
|
|
@@ -320,7 +454,7 @@ See [`CLAUDE.md`](./CLAUDE.md) for development guidelines and architectural rule
|
|
|
320
454
|
```markdown
|
|
321
455
|
## Contributing
|
|
322
456
|
|
|
323
|
-
Issues and pull requests are welcome. Run checks before submitting:
|
|
457
|
+
Issues and pull requests are welcome. Run checks and tests before submitting:
|
|
324
458
|
|
|
325
459
|
\`\`\`sh
|
|
326
460
|
bun run devcheck
|
|
@@ -343,8 +477,12 @@ Apache-2.0 — see [LICENSE](LICENSE) for details.
|
|
|
343
477
|
- **Accuracy over aspiration.** Only document what exists. Don't describe planned features as if they're implemented.
|
|
344
478
|
- **Tools first.** The tool surface is the most important content. Lead with it.
|
|
345
479
|
- **Tables over prose** for structured data (tools, config, directories). Scannable and diff-friendly.
|
|
346
|
-
- **Two-layer tool docs.**
|
|
480
|
+
- **Two-layer tool docs.** Grouping sentence + summary table for quick scanning, per-tool subsections for detail. Skip subsections for trivial tools.
|
|
481
|
+
- **Combined resources + prompts.** Single table with a `Type` column, not separate sections.
|
|
482
|
+
- **Promote hosted instances.** If there's a public URL, put it in a top-level callout under the badges — not buried in Getting Started.
|
|
483
|
+
- **Three install configs.** `bunx`, `npx`, `docker run` in that order. Each as a complete MCP-client JSON block.
|
|
347
484
|
- **Real names from code.** Tool names, env vars, and URIs must match the source exactly. Copy from the definitions, don't paraphrase.
|
|
348
|
-
- **Lowest friction first.**
|
|
485
|
+
- **Lowest friction first.** Hosted instance > bunx > npx > docker > clone.
|
|
349
486
|
- **No badges unless publishing.** Badges for unpublished packages are noise.
|
|
487
|
+
- **Client-agnostic framing.** Say "your MCP client configuration file", not `claude_desktop_config.json`.
|
|
350
488
|
- **Keep it current.** Update the README whenever tools are added or removed.
|
package/skills/setup/SKILL.md
CHANGED
|
@@ -4,14 +4,14 @@ 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.3"
|
|
8
8
|
audience: external
|
|
9
9
|
type: workflow
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
## Context
|
|
13
13
|
|
|
14
|
-
This skill assumes
|
|
14
|
+
This skill assumes `npx @cyanheads/mcp-ts-core init [name]` 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
|
|
|
@@ -91,7 +91,7 @@ mkdir -p .claude/skills && cp -R skills/* .claude/skills/
|
|
|
91
91
|
|
|
92
92
|
**For other agents** (Codex, Cursor, Windsurf, etc.) — copy to the equivalent directory (e.g., `.codex/skills/`, `.cursor/skills/`).
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
This step is the **bootstrap** — it creates the agent directory. From then on, use the `maintenance` skill to refresh it after package updates (Phase B). Maintenance only refreshes directories that already exist; it won't create a new agent directory on your behalf.
|
|
95
95
|
|
|
96
96
|
## Project Scaffolding
|
|
97
97
|
|
package/templates/AGENTS.md
CHANGED
|
@@ -14,8 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
1. **Read the framework API** — `node_modules/@cyanheads/mcp-ts-core/CLAUDE.md`
|
|
16
16
|
2. **Run the `setup` skill** — read `skills/setup/SKILL.md` and follow its checklist (project orientation, agent protocol file selection, echo definition cleanup, skill sync)
|
|
17
|
-
3. **
|
|
18
|
-
4. **Design the server** — read `skills/design-mcp-server/SKILL.md` and work through it with the user to map the domain into tools, resources, and services before scaffolding
|
|
17
|
+
3. **Design the server** — read `skills/design-mcp-server/SKILL.md` and work through it with the user to map the domain into tools, resources, and services before scaffolding
|
|
19
18
|
|
|
20
19
|
---
|
|
21
20
|
|
|
@@ -25,13 +24,13 @@ When the user asks what to do next, what's left, or needs direction, suggest rel
|
|
|
25
24
|
|
|
26
25
|
1. **Re-run the `setup` skill** — ensures CLAUDE.md, skills, structure, and metadata are populated and up to date with the current codebase
|
|
27
26
|
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
|
|
27
|
+
3. **Add tools/resources/prompts** — scaffold new definitions using the `add-tool`, `add-app-tool`, `add-resource`, `add-prompt` skills
|
|
29
28
|
4. **Add services** — scaffold domain service integrations using the `add-service` skill
|
|
30
29
|
5. **Add tests** — scaffold tests for existing definitions using the `add-test` skill
|
|
31
30
|
6. **Field-test definitions** — exercise tools/resources/prompts with real inputs using the `field-test` skill, get a report of issues and pain points
|
|
32
31
|
7. **Run `devcheck`** — lint, format, typecheck, and security audit
|
|
33
32
|
8. **Run the `polish-docs-meta` skill** — finalize README, CHANGELOG, metadata, and agent protocol for shipping
|
|
34
|
-
9. **Run the `maintenance` skill** —
|
|
33
|
+
9. **Run the `maintenance` skill** — investigate changelogs, adopt upstream changes, and sync skills after `bun update --latest`
|
|
35
34
|
|
|
36
35
|
Tailor suggestions to what's actually missing or stale — don't recite the full list every time.
|
|
37
36
|
|
|
@@ -77,6 +76,7 @@ export const searchItems = tool('search_items', {
|
|
|
77
76
|
|
|
78
77
|
// format() populates content[] — the only field most LLM clients forward to
|
|
79
78
|
// the model. Render all data the LLM needs, not just a count or title.
|
|
79
|
+
// Enforced at lint time: every field in `output` must appear in the rendered text.
|
|
80
80
|
format: (result) => [{
|
|
81
81
|
type: 'text',
|
|
82
82
|
text: result.items.map(i => `**${i.id}**: ${i.name}`).join('\n'),
|
|
@@ -122,20 +122,26 @@ export const reviewCode = prompt('review_code', {
|
|
|
122
122
|
|
|
123
123
|
```ts
|
|
124
124
|
// src/config/server-config.ts — lazy-parsed, separate from framework config
|
|
125
|
+
import { z } from '@cyanheads/mcp-ts-core';
|
|
126
|
+
import { parseEnvConfig } from '@cyanheads/mcp-ts-core/config';
|
|
127
|
+
|
|
125
128
|
const ServerConfigSchema = z.object({
|
|
126
|
-
|
|
129
|
+
apiKey: z.string().describe('External API key'),
|
|
127
130
|
maxResults: z.coerce.number().default(100),
|
|
128
131
|
});
|
|
132
|
+
|
|
129
133
|
let _config: z.infer<typeof ServerConfigSchema> | undefined;
|
|
130
134
|
export function getServerConfig() {
|
|
131
|
-
_config ??= ServerConfigSchema
|
|
132
|
-
|
|
133
|
-
maxResults:
|
|
135
|
+
_config ??= parseEnvConfig(ServerConfigSchema, {
|
|
136
|
+
apiKey: 'MY_API_KEY',
|
|
137
|
+
maxResults: 'MY_MAX_RESULTS',
|
|
134
138
|
});
|
|
135
139
|
return _config;
|
|
136
140
|
}
|
|
137
141
|
```
|
|
138
142
|
|
|
143
|
+
`parseEnvConfig` maps Zod schema paths → env var names so validation errors name the actual variable (`MY_API_KEY`) rather than the internal path (`apiKey`). It throws a `ConfigurationError` the framework catches and prints as a clean startup banner.
|
|
144
|
+
|
|
139
145
|
---
|
|
140
146
|
|
|
141
147
|
## Context
|
|
@@ -215,7 +221,7 @@ src/
|
|
|
215
221
|
|
|
216
222
|
Skills are modular instructions in `skills/` at the project root. Read them directly when a task matches — e.g., `skills/add-tool/SKILL.md` when adding a tool.
|
|
217
223
|
|
|
218
|
-
**Agent skill directory:** Copy skills into the directory your agent discovers (Claude Code: `.claude/skills/`, others: equivalent). This makes skills available as context without needing to reference `skills/` paths manually. After framework updates, re-
|
|
224
|
+
**Agent skill directory:** Copy skills into the directory your agent discovers (Claude Code: `.claude/skills/`, others: equivalent). This makes skills available as context without needing to reference `skills/` paths manually. After framework updates, run the `maintenance` skill — it re-syncs the agent directory automatically (Phase B).
|
|
219
225
|
|
|
220
226
|
Available skills:
|
|
221
227
|
|
|
@@ -232,7 +238,7 @@ Available skills:
|
|
|
232
238
|
| `field-test` | Exercise tools/resources/prompts with real inputs, verify behavior, report issues |
|
|
233
239
|
| `devcheck` | Lint, format, typecheck, audit |
|
|
234
240
|
| `polish-docs-meta` | Finalize docs, README, metadata, and agent protocol for shipping |
|
|
235
|
-
| `maintenance` |
|
|
241
|
+
| `maintenance` | Investigate changelogs, adopt upstream changes, sync skills to agent dirs |
|
|
236
242
|
| `report-issue-framework` | File a bug or feature request against `@cyanheads/mcp-ts-core` via `gh` CLI |
|
|
237
243
|
| `report-issue-local` | File a bug or feature request against this server's own repo via `gh` CLI |
|
|
238
244
|
| `api-auth` | Auth modes, scopes, JWT/OAuth |
|
|
@@ -250,6 +256,8 @@ When you complete a skill's checklist, check the boxes and add a completion time
|
|
|
250
256
|
|
|
251
257
|
## Commands
|
|
252
258
|
|
|
259
|
+
**Runtime:** Scripts use `tsx` — both `npm run <cmd>` and `bun run <cmd>` work. Use whichever package manager you have; `bun` is slightly faster for invoking scripts but not required.
|
|
260
|
+
|
|
253
261
|
| Command | Purpose |
|
|
254
262
|
|:--------|:--------|
|
|
255
263
|
| `npm run build` | Compile TypeScript |
|
|
@@ -281,7 +289,7 @@ import { getMyService } from '@/services/my-domain/my-service.js';
|
|
|
281
289
|
|
|
282
290
|
## Checklist
|
|
283
291
|
|
|
284
|
-
- [ ] Zod schemas: all fields have `.describe()`, only JSON-Schema-serializable types (no `z.custom()`, `z.date()`, `z.transform()`,
|
|
292
|
+
- [ ] Zod schemas: all fields have `.describe()`, only JSON-Schema-serializable types (no `z.custom()`, `z.date()`, `z.transform()`, `z.bigint()`, `z.symbol()`, `z.void()`, `z.map()`, `z.set()`, `z.function()`, `z.nan()`)
|
|
285
293
|
- [ ] Optional nested objects: handler guards for empty inner values from form-based clients (`if (input.obj?.field && ...)`, not just `if (input.obj)`)
|
|
286
294
|
- [ ] JSDoc `@fileoverview` + `@module` on every file
|
|
287
295
|
- [ ] `ctx.log` for logging, `ctx.state` for storage
|