@cyanheads/mcp-ts-core 0.1.4 → 0.1.8
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 +5 -1
- package/README.md +1 -1
- package/dist/core/app.d.ts +2 -0
- package/dist/core/app.d.ts.map +1 -1
- package/dist/core/app.js +19 -4
- package/dist/core/app.js.map +1 -1
- package/dist/core/context.d.ts +2 -2
- package/dist/core/context.d.ts.map +1 -1
- package/dist/core/context.js +9 -5
- package/dist/core/context.js.map +1 -1
- package/dist/mcp-server/resources/utils/resourceHandlerFactory.d.ts.map +1 -1
- package/dist/mcp-server/resources/utils/resourceHandlerFactory.js +4 -2
- package/dist/mcp-server/resources/utils/resourceHandlerFactory.js.map +1 -1
- package/dist/mcp-server/server.d.ts +6 -0
- package/dist/mcp-server/server.d.ts.map +1 -1
- package/dist/mcp-server/server.js +2 -11
- package/dist/mcp-server/server.js.map +1 -1
- package/dist/mcp-server/tasks/core/taskManager.js +1 -1
- package/dist/mcp-server/tasks/core/taskManager.js.map +1 -1
- package/dist/mcp-server/tools/tool-registration.d.ts.map +1 -1
- package/dist/mcp-server/tools/tool-registration.js +28 -12
- package/dist/mcp-server/tools/tool-registration.js.map +1 -1
- package/dist/mcp-server/tools/utils/toolHandlerFactory.d.ts.map +1 -1
- package/dist/mcp-server/tools/utils/toolHandlerFactory.js +12 -2
- package/dist/mcp-server/tools/utils/toolHandlerFactory.js.map +1 -1
- package/dist/mcp-server/transports/auth/authMiddleware.js +1 -1
- package/dist/mcp-server/transports/auth/authMiddleware.js.map +1 -1
- package/dist/mcp-server/transports/auth/lib/authUtils.d.ts.map +1 -1
- package/dist/mcp-server/transports/auth/lib/authUtils.js +3 -2
- package/dist/mcp-server/transports/auth/lib/authUtils.js.map +1 -1
- package/dist/mcp-server/transports/auth/lib/checkScopes.d.ts.map +1 -1
- package/dist/mcp-server/transports/auth/lib/checkScopes.js +4 -4
- package/dist/mcp-server/transports/auth/lib/checkScopes.js.map +1 -1
- package/dist/mcp-server/transports/http/httpTransport.d.ts.map +1 -1
- package/dist/mcp-server/transports/http/httpTransport.js +28 -18
- package/dist/mcp-server/transports/http/httpTransport.js.map +1 -1
- package/dist/mcp-server/transports/http/sessionStore.d.ts.map +1 -1
- package/dist/mcp-server/transports/http/sessionStore.js +23 -13
- package/dist/mcp-server/transports/http/sessionStore.js.map +1 -1
- package/dist/services/graph/core/GraphService.js +2 -2
- package/dist/services/graph/core/GraphService.js.map +1 -1
- package/dist/services/llm/providers/openrouter.provider.js +1 -1
- package/dist/services/llm/providers/openrouter.provider.js.map +1 -1
- package/dist/services/speech/core/speechMetrics.js +1 -1
- package/dist/services/speech/core/speechMetrics.js.map +1 -1
- package/dist/services/speech/providers/elevenlabs.provider.js +1 -1
- package/dist/services/speech/providers/elevenlabs.provider.js.map +1 -1
- package/dist/services/speech/providers/whisper.provider.js +1 -1
- package/dist/services/speech/providers/whisper.provider.js.map +1 -1
- package/dist/storage/core/StorageService.js +2 -2
- package/dist/storage/core/StorageService.js.map +1 -1
- package/dist/storage/core/storageValidation.d.ts.map +1 -1
- package/dist/storage/core/storageValidation.js +0 -13
- package/dist/storage/core/storageValidation.js.map +1 -1
- package/dist/utils/index.d.ts +2 -2
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +3 -3
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/internal/error-handler/errorHandler.js +1 -1
- package/dist/utils/internal/error-handler/errorHandler.js.map +1 -1
- package/dist/utils/internal/performance.d.ts +10 -19
- package/dist/utils/internal/performance.d.ts.map +1 -1
- package/dist/utils/internal/performance.js +35 -118
- package/dist/utils/internal/performance.js.map +1 -1
- package/dist/utils/internal/requestContext.d.ts.map +1 -1
- package/dist/utils/internal/requestContext.js +13 -10
- package/dist/utils/internal/requestContext.js.map +1 -1
- package/dist/utils/telemetry/{semconv.d.ts → attributes.d.ts} +14 -129
- package/dist/utils/telemetry/attributes.d.ts.map +1 -0
- package/dist/utils/telemetry/{semconv.js → attributes.js} +27 -148
- package/dist/utils/telemetry/attributes.js.map +1 -0
- package/dist/utils/telemetry/index.d.ts +3 -3
- package/dist/utils/telemetry/index.d.ts.map +1 -1
- package/dist/utils/telemetry/index.js +3 -3
- package/dist/utils/telemetry/index.js.map +1 -1
- package/dist/utils/telemetry/instrumentation.d.ts.map +1 -1
- package/dist/utils/telemetry/instrumentation.js +23 -19
- package/dist/utils/telemetry/instrumentation.js.map +1 -1
- package/dist/utils/telemetry/metrics.d.ts +0 -64
- package/dist/utils/telemetry/metrics.d.ts.map +1 -1
- package/dist/utils/telemetry/metrics.js +0 -78
- package/dist/utils/telemetry/metrics.js.map +1 -1
- package/package.json +14 -14
- package/skills/add-test/SKILL.md +216 -0
- package/skills/api-utils/SKILL.md +5 -7
- package/skills/design-mcp-server/SKILL.md +153 -9
- package/skills/polish-docs-meta/SKILL.md +137 -0
- package/skills/polish-docs-meta/references/agent-protocol.md +78 -0
- package/skills/polish-docs-meta/references/package-meta.md +63 -0
- package/skills/polish-docs-meta/references/readme.md +183 -0
- package/skills/polish-docs-meta/references/server-json.md +142 -0
- package/skills/release/SKILL.md +102 -30
- package/skills/setup/SKILL.md +3 -2
- package/templates/.env.example +6 -1
- package/templates/AGENTS.md +3 -1
- package/templates/CLAUDE.md +3 -1
- package/templates/Dockerfile +84 -0
- package/templates/_.gitignore +6 -0
- package/templates/package.json +3 -0
- package/templates/src/mcp-server/tools/definitions/echo.tool.ts +2 -0
- package/dist/utils/telemetry/semconv.d.ts.map +0 -1
- package/dist/utils/telemetry/semconv.js.map +0 -1
|
@@ -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: "
|
|
7
|
+
version: "2.0"
|
|
8
8
|
audience: external
|
|
9
9
|
type: workflow
|
|
10
10
|
---
|
|
@@ -69,19 +69,160 @@ This is the raw material. Not everything becomes a tool.
|
|
|
69
69
|
**Common traps:**
|
|
70
70
|
|
|
71
71
|
- **Everything-is-a-tool**: "Fetch by ID" with no other params is a resource. Resources let clients inject context without a tool call.
|
|
72
|
-
- **CRUD explosion**: Don't map every REST endpoint to a tool.
|
|
72
|
+
- **CRUD explosion**: Don't map every REST endpoint to a tool. Related operations on the same noun often belong in one tool with an `operation`/`mode` parameter (see Step 4).
|
|
73
73
|
- **Ignoring resources**: If the server has reference data, schemas, or entities the LLM should read — expose them as resources.
|
|
74
|
+
- **1:1 endpoint mirroring**: API endpoints are designed for programmatic consumers. LLM tools should be designed for workflows — what an agent is *trying to accomplish*, not what HTTP calls happen under the hood.
|
|
74
75
|
|
|
75
76
|
### 4. Design Tools
|
|
76
77
|
|
|
77
|
-
|
|
78
|
+
This is the highest-leverage step. Tool definitions — names, descriptions, parameters, output schemas — are the **entire interface contract** the LLM reads to decide whether and how to call a tool. Every field is context. Design accordingly.
|
|
79
|
+
|
|
80
|
+
#### Think in workflows, not endpoints
|
|
81
|
+
|
|
82
|
+
The unit of a tool is a *useful action*, not an API call. Ask: "What is the agent trying to accomplish?" — not "What endpoints does the API have?"
|
|
83
|
+
|
|
84
|
+
A single tool can call multiple APIs internally, apply local filtering, reshape data, and return enriched results. The LLM doesn't know or care about the underlying calls.
|
|
85
|
+
|
|
86
|
+
**Consolidation via operation/mode enum.** When a domain noun has several related operations that share parameters, consolidate into one tool with a discriminated parameter. This keeps the tool surface small and lets the LLM discover all capabilities in one place.
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
// One tool for all branch operations — not five separate tools
|
|
90
|
+
const gitBranch = tool('git_branch', {
|
|
91
|
+
description: 'Manage branches: list, show current, create, delete, or rename.',
|
|
92
|
+
input: z.object({
|
|
93
|
+
operation: z.enum(['list', 'create', 'delete', 'rename', 'show-current'])
|
|
94
|
+
.describe('Branch operation to perform.'),
|
|
95
|
+
name: z.string().optional().describe('Branch name (required for create/delete/rename).'),
|
|
96
|
+
newName: z.string().optional().describe('New name (required for rename).'),
|
|
97
|
+
}),
|
|
98
|
+
// ...
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
// Workflow tool — search + local filter pipeline, not a raw API proxy
|
|
104
|
+
const findEligibleStudies = tool('clinicaltrials_find_eligible_studies', {
|
|
105
|
+
description: 'Matches patient demographics and medical profile to eligible clinical trials. '
|
|
106
|
+
+ 'Filters by age, sex, conditions, location, and healthy volunteer status. '
|
|
107
|
+
+ 'Returns ranked list of matching studies with eligibility explanations.',
|
|
108
|
+
// handler: listStudies() → filter by eligibility → rank by location proximity → slice
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**When to consolidate vs. split:**
|
|
113
|
+
|
|
114
|
+
| Consolidate (one tool) | Split (separate tools) |
|
|
115
|
+
|:------------------------|:-----------------------|
|
|
116
|
+
| Operations share the same noun and most parameters | Operations have fundamentally different inputs/outputs |
|
|
117
|
+
| Related CRUD on a single entity | Read-only lookup vs. multi-step workflow |
|
|
118
|
+
| Agent would naturally think of them together | Agent would use them in different contexts |
|
|
119
|
+
|
|
120
|
+
There is no fixed ceiling on tool count — tools need to earn their keep, but don't artificially limit the surface. If the domain genuinely has 20 distinct workflows, expose 20 tools.
|
|
121
|
+
|
|
122
|
+
#### Tool descriptions
|
|
123
|
+
|
|
124
|
+
The description is the LLM's primary signal for tool selection. It must answer: *what does this do, and when should I use it?*
|
|
125
|
+
|
|
126
|
+
- **Be concrete about capability.** "Search for clinical trial studies using queries and filters" beats "Interact with studies."
|
|
127
|
+
- **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.
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
// Good — describes a prerequisite the LLM must know
|
|
131
|
+
description: 'Set the session working directory for all git operations. '
|
|
132
|
+
+ 'This allows subsequent git commands to omit the path parameter.'
|
|
133
|
+
|
|
134
|
+
// Good — self-explanatory, no workflow hints needed
|
|
135
|
+
description: 'Show the working tree status including staged, unstaged, and untracked files.'
|
|
136
|
+
|
|
137
|
+
// Good — warns about constraints
|
|
138
|
+
description: 'Fetches trial results data for completed studies. '
|
|
139
|
+
+ 'Only available for studies where hasResults is true.'
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Context-dependent: a simple read-only tool needs a one-line description. A tool with prerequisites, modes, or non-obvious behavior needs more. Match depth of description to complexity of tool.
|
|
143
|
+
|
|
144
|
+
#### Parameter descriptions
|
|
145
|
+
|
|
146
|
+
Every `.describe()` is prompt text the LLM reads. Parameters should convey: what the value is, what it affects, and (where non-obvious) how to use it well.
|
|
147
|
+
|
|
148
|
+
- **Constrain the type.** Enums and literals over free strings. Regex validation for formatted IDs. Ranges for numeric bounds.
|
|
149
|
+
- **Explain costs and tradeoffs** when a parameter choice has meaningful consequences.
|
|
150
|
+
- **Name alternative approaches** when a simpler path exists.
|
|
151
|
+
- **Include format patterns** for structured values, but don't pad descriptions with redundant examples.
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
// Good — explains cost, recommends action, names the alternative
|
|
155
|
+
fields: z.array(z.string()).optional()
|
|
156
|
+
.describe('Specific fields to return (reduces payload size). '
|
|
157
|
+
+ 'STRONGLY RECOMMENDED — without this, the full study record (~70KB each) is returned. '
|
|
158
|
+
+ 'Use full data only when you need detailed eligibility criteria, locations, or results.'),
|
|
159
|
+
|
|
160
|
+
// Good — explains what the flag does AND how to override
|
|
161
|
+
autoExclude: z.boolean().default(true)
|
|
162
|
+
.describe('Automatically exclude lock files and generated files from diff output '
|
|
163
|
+
+ 'to reduce context bloat. Set to false if you need to inspect these files.'),
|
|
164
|
+
|
|
165
|
+
// Good — names the format and gives one example
|
|
166
|
+
nctIds: z.union([z.string(), z.array(z.string()).max(5)])
|
|
167
|
+
.describe('A single NCT ID (e.g., "NCT12345678") or an array of up to 5 NCT IDs to fetch.'),
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
#### Output design
|
|
171
|
+
|
|
172
|
+
The output schema and `format` function control what the LLM reads back. Design for the agent's *next decision*, not for a UI or an API consumer.
|
|
173
|
+
|
|
174
|
+
**Principles:**
|
|
175
|
+
|
|
176
|
+
- **Include IDs and references for chaining.** If the agent might act on a result, return the identifiers it needs for follow-up tool calls.
|
|
177
|
+
- **Curate vs. pass-through depends on domain.** Medical/scientific data — don't trim fields that could alter correctness. CRUD responses — return what the agent needs, not the full API payload. Match fidelity to consequence.
|
|
178
|
+
- **Surface what was done, not just results.** After a write operation, include the new state. (`git_commit` auto-includes post-commit `git status`. The LLM sees the repo state without an extra round trip.)
|
|
179
|
+
- **Communicate filtering.** If the tool silently excluded content, tell the LLM what was excluded and how to get it back. The agent can't act on what it doesn't know about.
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
// git_diff — when lock files are filtered, the output tells the LLM
|
|
183
|
+
output: z.object({
|
|
184
|
+
diff: z.string().describe('Unified diff output.'),
|
|
185
|
+
excludedFiles: z.array(z.string()).optional()
|
|
186
|
+
.describe('Files automatically excluded from the diff (e.g., lock files). '
|
|
187
|
+
+ 'Call again with autoExclude=false to include them.'),
|
|
188
|
+
}),
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
- **Truncate large output with counts.** When a list exceeds a reasonable display size, show the top N and append "...and X more". Don't silently drop results.
|
|
192
|
+
- **Use the `format` function for readable summaries** while keeping the full structured data in the output object for programmatic use.
|
|
193
|
+
|
|
194
|
+
#### Error messages as LLM guidance
|
|
195
|
+
|
|
196
|
+
When a tool throws, the error message is the agent's only signal for recovery. A good error message tells the LLM *what happened and what to do next*.
|
|
197
|
+
|
|
198
|
+
```ts
|
|
199
|
+
// Bad — the LLM has no recovery path
|
|
200
|
+
throw new Error('Not found');
|
|
201
|
+
|
|
202
|
+
// Good — names both resolution options
|
|
203
|
+
"No session working directory set. Please specify a 'path' or use 'git_set_working_dir' first."
|
|
204
|
+
|
|
205
|
+
// Good — structured hint in error data
|
|
206
|
+
throw new McpError(JsonRpcErrorCode.Forbidden,
|
|
207
|
+
"Cannot perform 'reset --hard' on protected branch 'main' without explicit confirmation.",
|
|
208
|
+
{ branch: 'main', operation: 'reset --hard', hint: 'Set the confirmed parameter to true to proceed.' },
|
|
209
|
+
);
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Think about the common failure modes for each tool and write error messages that guide recovery. This is part of the tool's interface design, not an afterthought.
|
|
213
|
+
|
|
214
|
+
#### Design table
|
|
215
|
+
|
|
216
|
+
Summarize each tool:
|
|
78
217
|
|
|
79
218
|
| Aspect | Decision |
|
|
80
219
|
|:-------|:---------|
|
|
81
220
|
| **Name** | `snake_case`, verb-noun: `search_papers`, `create_task`. Prefix with server domain if ambiguous. |
|
|
82
|
-
| **Granularity** | One tool per user
|
|
83
|
-
| **
|
|
84
|
-
| **
|
|
221
|
+
| **Granularity** | One tool per user-meaningful workflow, not per API call. Consolidate related operations with `operation`/`mode` enum. |
|
|
222
|
+
| **Description** | Concrete capability statement. Add operational guidance (prerequisites, constraints, gotchas) when non-obvious. |
|
|
223
|
+
| **Input schema** | `.describe()` on every field. Constrained types (enums, literals, regex). Explain costs/tradeoffs of parameter choices. |
|
|
224
|
+
| **Output schema** | Designed for the LLM's next action. Include chaining IDs. Communicate filtering. Post-write state where useful. |
|
|
225
|
+
| **Error messages** | Name what went wrong and what the LLM should do about it. Include hints for common recovery paths. |
|
|
85
226
|
| **Annotations** | `readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint`. Helps clients auto-approve safely. |
|
|
86
227
|
| **Auth scopes** | `tool:noun:read`, `tool:noun:write`. Skip for read-only or stdio-only servers. |
|
|
87
228
|
|
|
@@ -180,10 +321,13 @@ Execute the plan using the scaffolding skills:
|
|
|
180
321
|
- [ ] External APIs/dependencies researched and verified (docs fetched, SDKs identified)
|
|
181
322
|
- [ ] Domain operations mapped (nouns + verbs)
|
|
182
323
|
- [ ] Each operation classified as tool, resource, prompt, or excluded
|
|
183
|
-
- [ ]
|
|
184
|
-
- [ ] Tool
|
|
324
|
+
- [ ] Related operations consolidated (operation/mode enum) — not one tool per endpoint
|
|
325
|
+
- [ ] Tool descriptions are concrete and include operational guidance where non-obvious
|
|
326
|
+
- [ ] Parameter `.describe()` text explains what the value is, what it affects, and tradeoffs
|
|
327
|
+
- [ ] Input schemas use constrained types (enums, literals, regex) over free strings
|
|
328
|
+
- [ ] Output schemas designed for LLM's next action — chaining IDs, post-write state, filtering communicated
|
|
329
|
+
- [ ] Error messages guide recovery — name what went wrong and what to do next
|
|
185
330
|
- [ ] Annotations set correctly (`readOnlyHint`, `destructiveHint`, etc.)
|
|
186
|
-
- [ ] Input schemas use constrained types (enums, literals) where the domain allows
|
|
187
331
|
- [ ] Resource URIs use `{param}` templates, pagination planned for large lists
|
|
188
332
|
- [ ] Service layer planned (or explicitly skipped with reasoning)
|
|
189
333
|
- [ ] Server config env vars identified
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: polish-docs-meta
|
|
3
|
+
description: >
|
|
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
|
+
metadata:
|
|
6
|
+
author: cyanheads
|
|
7
|
+
version: "1.0"
|
|
8
|
+
audience: external
|
|
9
|
+
type: workflow
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## When to Use
|
|
13
|
+
|
|
14
|
+
- Server implementation is functionally complete (tools, resources, prompts, services all working)
|
|
15
|
+
- `bun run devcheck` passes, tests pass
|
|
16
|
+
- You're preparing for first commit, first release, or making the repo public
|
|
17
|
+
- User says "polish", "polish docs", "finalize", "make it ship-ready", "clean up docs", or similar
|
|
18
|
+
- Re-running after adding/removing tools, resources, or other surface area changes
|
|
19
|
+
|
|
20
|
+
Prefer running after implementation is complete, but safe to re-run at any point — steps are idempotent.
|
|
21
|
+
|
|
22
|
+
## Prerequisites
|
|
23
|
+
|
|
24
|
+
- [ ] All tools/resources/prompts implemented and registered
|
|
25
|
+
- [ ] `bun run devcheck` passes
|
|
26
|
+
- [ ] Tests pass (`npm test`)
|
|
27
|
+
|
|
28
|
+
If these aren't met, address them first.
|
|
29
|
+
|
|
30
|
+
## Steps
|
|
31
|
+
|
|
32
|
+
### 1. Audit the Surface Area
|
|
33
|
+
|
|
34
|
+
Read all tool, resource, and prompt definitions. Build a mental model of what the server actually does — names, descriptions, input/output shapes, auth scopes. This inventory drives every document below.
|
|
35
|
+
|
|
36
|
+
Read:
|
|
37
|
+
- `src/index.ts` (what's registered in `createApp()`)
|
|
38
|
+
- All files in `src/mcp-server/tools/definitions/`
|
|
39
|
+
- All files in `src/mcp-server/resources/definitions/`
|
|
40
|
+
- All files in `src/mcp-server/prompts/definitions/`
|
|
41
|
+
- All files in `src/services/` (if any)
|
|
42
|
+
- `src/config/server-config.ts` (if any)
|
|
43
|
+
|
|
44
|
+
Capture: tool count, resource count, prompt count, service count, required env vars.
|
|
45
|
+
|
|
46
|
+
### 2. README.md
|
|
47
|
+
|
|
48
|
+
Read `references/readme.md` for structure and conventions. If `README.md` doesn't exist, create it from scratch. If it exists, diff the current content against the audit — update tool/resource/prompt tables, env var lists, and descriptions to match the actual surface area. Don't rewrite sections that are already accurate.
|
|
49
|
+
|
|
50
|
+
### 3. Agent Protocol (CLAUDE.md / AGENTS.md)
|
|
51
|
+
|
|
52
|
+
Update the project's agent protocol file to reflect the actual server.
|
|
53
|
+
|
|
54
|
+
Read `references/agent-protocol.md` for the full update checklist, then review the current file and address what's stale or missing:
|
|
55
|
+
|
|
56
|
+
- If a "First Session" onboarding block is still present, remove it
|
|
57
|
+
- If example patterns still use generic/template names (e.g., `searchItems`, `itemData`), replace with real definitions from this server
|
|
58
|
+
- If server-specific skills were added, update the skills table
|
|
59
|
+
- Verify the structure diagram matches the actual directory layout
|
|
60
|
+
- If custom scripts were added to `package.json`, update the commands table
|
|
61
|
+
|
|
62
|
+
### 4. `.env.example`
|
|
63
|
+
|
|
64
|
+
Compare `.env.example` against the server config Zod schema. Add any missing server-specific vars with a comment and default (if any). Remove vars for features that no longer exist. Group by category. Preserve existing framework vars that are still relevant.
|
|
65
|
+
|
|
66
|
+
### 5. `package.json` Metadata
|
|
67
|
+
|
|
68
|
+
Check for empty or placeholder metadata fields. Read `references/package-meta.md` for which fields matter and why. Fill in anything still missing — skip fields that are already correct.
|
|
69
|
+
|
|
70
|
+
Key fields: `description`, `repository`, `author`, `homepage`, `bugs`, `keywords`.
|
|
71
|
+
|
|
72
|
+
### 6. `CHANGELOG.md`
|
|
73
|
+
|
|
74
|
+
If `CHANGELOG.md` doesn't exist, create it with an initial entry. If it exists, verify the latest entry reflects the current state:
|
|
75
|
+
|
|
76
|
+
```markdown
|
|
77
|
+
# Changelog
|
|
78
|
+
|
|
79
|
+
## 0.1.0 — YYYY-MM-DD
|
|
80
|
+
|
|
81
|
+
Initial release.
|
|
82
|
+
|
|
83
|
+
### Added
|
|
84
|
+
- [list tools, resources, prompts, key capabilities]
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Use a concrete version and date. Never `[Unreleased]`.
|
|
88
|
+
|
|
89
|
+
### 7. `LICENSE`
|
|
90
|
+
|
|
91
|
+
Confirm a license file exists. If not, ask the user which license to use (default: Apache-2.0, matching the scaffolded `package.json`). Create the file.
|
|
92
|
+
|
|
93
|
+
### 8. `Dockerfile`
|
|
94
|
+
|
|
95
|
+
If a `Dockerfile` exists, verify the OCI labels and runtime config match the actual server:
|
|
96
|
+
|
|
97
|
+
- `org.opencontainers.image.title` matches the package name
|
|
98
|
+
- `org.opencontainers.image.description` is filled in (not empty placeholder)
|
|
99
|
+
- `org.opencontainers.image.source` points to the real repository URL (add if missing)
|
|
100
|
+
- Log directory path in `mkdir` and `LOGS_DIR` uses the correct server name
|
|
101
|
+
|
|
102
|
+
If no `Dockerfile` exists and the server is deployed via HTTP transport, consider scaffolding one — the template is available via `npx @cyanheads/mcp-ts-core init`.
|
|
103
|
+
|
|
104
|
+
### 9. `docs/tree.md`
|
|
105
|
+
|
|
106
|
+
Regenerate the directory structure:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
bun run tree
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Review the output for anything unexpected (leftover files, missing directories).
|
|
113
|
+
|
|
114
|
+
### 10. Final Verification
|
|
115
|
+
|
|
116
|
+
Run the full check suite one last time:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
bun run devcheck
|
|
120
|
+
npm test
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Both must pass clean.
|
|
124
|
+
|
|
125
|
+
## Checklist
|
|
126
|
+
|
|
127
|
+
- [ ] Surface area audited — tool/resource/prompt/service inventory built
|
|
128
|
+
- [ ] `README.md` accurate — tool/resource tables, config, descriptions match actual code
|
|
129
|
+
- [ ] Agent protocol file accurate — no stale template content, real examples, structure matches reality
|
|
130
|
+
- [ ] `.env.example` in sync with server config schema
|
|
131
|
+
- [ ] `package.json` metadata complete (`description`, `repository`, `author`, `keywords`)
|
|
132
|
+
- [ ] `CHANGELOG.md` exists with current entry
|
|
133
|
+
- [ ] `LICENSE` file present
|
|
134
|
+
- [ ] `Dockerfile` OCI labels and runtime config accurate (if present)
|
|
135
|
+
- [ ] `docs/tree.md` regenerated
|
|
136
|
+
- [ ] `bun run devcheck` passes
|
|
137
|
+
- [ ] `npm test` passes
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Finalizing the Agent Protocol File
|
|
2
|
+
|
|
3
|
+
Guide for updating the project's `CLAUDE.md` or `AGENTS.md` to reflect the actual server. The file may still contain scaffolded template content (onboarding blocks, generic examples) or may have been partially updated — review the current state and address what's stale or missing.
|
|
4
|
+
|
|
5
|
+
## What to Update
|
|
6
|
+
|
|
7
|
+
### 1. Strip the "First Session" Block (if present)
|
|
8
|
+
|
|
9
|
+
The scaffolded template includes a `## First Session` section with one-time onboarding steps. If this section is still present, delete it entirely (header through the `---` separator after it). If it's already been removed, skip this step.
|
|
10
|
+
|
|
11
|
+
**What it looks like:**
|
|
12
|
+
|
|
13
|
+
```markdown
|
|
14
|
+
## First Session
|
|
15
|
+
|
|
16
|
+
> **Remove this section** from CLAUDE.md / AGENTS.md after completing these steps.
|
|
17
|
+
|
|
18
|
+
1. **Read the framework API** — ...
|
|
19
|
+
2. **Run the `setup` skill** — ...
|
|
20
|
+
3. **Design the server** — ...
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### 2. Replace Example Patterns with Real Definitions
|
|
26
|
+
|
|
27
|
+
Check the Patterns section for generic template examples (e.g., `searchItems`, `itemData`, `reviewCode`). If still present, replace them with actual tool/resource/prompt definitions from the server — or the most representative ones if there are many. If the examples already reflect real definitions, verify they're still accurate.
|
|
28
|
+
|
|
29
|
+
Pick examples that:
|
|
30
|
+
- Show the most common or important capability
|
|
31
|
+
- Demonstrate any non-trivial patterns the server uses (e.g., `ctx.state`, `ctx.elicit`, `task: true`, services)
|
|
32
|
+
- Include a handler with real business logic, not just passthrough
|
|
33
|
+
|
|
34
|
+
Keep 1-2 examples per primitive type (tool, resource, prompt). Don't list every definition — the README handles that.
|
|
35
|
+
|
|
36
|
+
### 3. Update the Structure Diagram
|
|
37
|
+
|
|
38
|
+
Compare the structure diagram against the actual directory layout. If it still reflects the generic template or has fallen out of date:
|
|
39
|
+
|
|
40
|
+
- Add directories/files that exist but aren't listed (e.g., `config/server-config.ts`, service directories, `worker.ts`)
|
|
41
|
+
- Remove entries for directories that don't exist (e.g., if no prompts were added, remove the prompts line)
|
|
42
|
+
- Verify nesting and naming match reality
|
|
43
|
+
|
|
44
|
+
### 4. Update the Context Table
|
|
45
|
+
|
|
46
|
+
Review the `ctx` feature table. Remove rows for features the server doesn't use (e.g., `ctx.elicit`, `ctx.sample` if no tools call them). Add any custom context usage that's become important. The table should reflect what this server actually uses, not the full framework surface.
|
|
47
|
+
|
|
48
|
+
### 5. Update Server Config Example
|
|
49
|
+
|
|
50
|
+
If the server has a `server-config.ts`, check whether the Patterns section still shows a generic config example. If so, replace it with the actual schema (or a representative subset). If the server has no custom config, remove the config example entirely.
|
|
51
|
+
|
|
52
|
+
### 6. Update the Skills Table
|
|
53
|
+
|
|
54
|
+
Check for server-specific skills added to `skills/` that aren't in the table yet. Add any missing entries. Remove framework skills the server doesn't use (rare — most are useful).
|
|
55
|
+
|
|
56
|
+
### 7. Update the Commands Table
|
|
57
|
+
|
|
58
|
+
Compare the commands table against `package.json` scripts. Add any custom scripts that are missing. Remove or rename entries that no longer match. The table should reflect the current `scripts` block.
|
|
59
|
+
|
|
60
|
+
### 8. Update the Checklist
|
|
61
|
+
|
|
62
|
+
Review the checklist for completeness. Add server-specific items that are missing (e.g., required env vars, external service dependencies, custom naming conventions). Remove items that don't apply to this server.
|
|
63
|
+
|
|
64
|
+
## What to Preserve
|
|
65
|
+
|
|
66
|
+
These sections should remain intact unless you have a specific reason to change them:
|
|
67
|
+
|
|
68
|
+
- **Core Rules** — universal to all servers built on the framework
|
|
69
|
+
- **Errors section** — the three-level escalation pattern is universal
|
|
70
|
+
- **Imports section** — keep unless the alias convention was changed
|
|
71
|
+
- **Framework reference pointer** — the line directing agents to `node_modules/@cyanheads/mcp-ts-core/CLAUDE.md`
|
|
72
|
+
|
|
73
|
+
## Pitfalls
|
|
74
|
+
|
|
75
|
+
- Don't duplicate the full framework CLAUDE.md into the project file. The project file covers server-specific conventions; the framework file covers the API. The pointer at the top connects them.
|
|
76
|
+
- Don't remove `## Core Rules` even if it seems obvious — agents read this fresh each session.
|
|
77
|
+
- Don't add implementation details that change frequently. The agent protocol file should be stable — update it when the server's shape changes, not on every commit.
|
|
78
|
+
- Don't assume this is a one-time pass. The protocol file should be revisited whenever the server's surface area changes (tools added/removed, new services, config changes).
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# package.json Metadata
|
|
2
|
+
|
|
3
|
+
Fields that may still be empty or generic from scaffolding. Check each one and fill in anything that's missing or placeholder.
|
|
4
|
+
|
|
5
|
+
## Fields to Check
|
|
6
|
+
|
|
7
|
+
| Field | Default / Scaffolded | What It Should Be |
|
|
8
|
+
|:------|:---------------------|:------------------|
|
|
9
|
+
| `name` | `{{PACKAGE_NAME}}` (substituted by init) | Verify it's correct. Use scoped name if publishing (`@org/my-server`). |
|
|
10
|
+
| `version` | `0.1.0` | Keep for initial development. Bump via the `release` skill. |
|
|
11
|
+
| `description` | `""` (empty) | One sentence: what the server does and what it wraps. Appears on npm and in `npm search`. |
|
|
12
|
+
| `repository` | _(often missing)_ | `{ "type": "git", "url": "https://github.com/org/repo.git" }` |
|
|
13
|
+
| `homepage` | _(often missing)_ | Repository URL or docs URL. |
|
|
14
|
+
| `bugs` | _(often missing)_ | `{ "url": "https://github.com/org/repo/issues" }` |
|
|
15
|
+
| `author` | _(often missing)_ | `"Name <email>"` or `{ "name": "...", "email": "..." }` |
|
|
16
|
+
| `keywords` | `["mcp", "mcp-server", "model-context-protocol"]` | Add domain-specific keywords. Keep the MCP ones. |
|
|
17
|
+
| `license` | `Apache-2.0` | Change if using a different license. Must match the LICENSE file. |
|
|
18
|
+
|
|
19
|
+
## Fields That Should Be Correct
|
|
20
|
+
|
|
21
|
+
These are set by `init` and generally don't need changes. Verify they're present and correct:
|
|
22
|
+
|
|
23
|
+
| Field | Value | Why |
|
|
24
|
+
|:------|:------|:----|
|
|
25
|
+
| `type` | `"module"` | ESM — required by the framework |
|
|
26
|
+
| `main` | `"dist/index.js"` | Entry point after build |
|
|
27
|
+
| `types` | `"dist/index.d.ts"` | TypeScript declarations |
|
|
28
|
+
| `files` | `["dist/"]` | What npm publishes |
|
|
29
|
+
| `engines` | `{ "node": ">=22.0.0" }` | Minimum Node version |
|
|
30
|
+
| `scripts` | _(various)_ | Build, dev, test scripts |
|
|
31
|
+
| `dependencies` | `@cyanheads/mcp-ts-core`, `pino-pretty` | Core framework + log formatting |
|
|
32
|
+
|
|
33
|
+
## Keywords
|
|
34
|
+
|
|
35
|
+
Good keywords improve npm discoverability. Include:
|
|
36
|
+
|
|
37
|
+
1. The base MCP keywords (already scaffolded): `mcp`, `mcp-server`, `model-context-protocol`
|
|
38
|
+
2. The domain: `project-management`, `task-tracking`, `acme-api`
|
|
39
|
+
3. The transport if non-default: `http`, `sse`, `cloudflare-workers`
|
|
40
|
+
|
|
41
|
+
Example:
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
"keywords": [
|
|
45
|
+
"mcp",
|
|
46
|
+
"mcp-server",
|
|
47
|
+
"model-context-protocol",
|
|
48
|
+
"acme",
|
|
49
|
+
"project-management",
|
|
50
|
+
"task-tracking"
|
|
51
|
+
]
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Publishing Checklist
|
|
55
|
+
|
|
56
|
+
If publishing to npm, also verify these (skip for private/internal servers):
|
|
57
|
+
|
|
58
|
+
- `name` doesn't conflict with an existing package
|
|
59
|
+
- `publishConfig.access` is `"public"` (already set by init for scoped packages)
|
|
60
|
+
- `files` includes everything needed at runtime (`dist/` is correct for most servers)
|
|
61
|
+
- `bin` is set if the server should be runnable via `npx` (add `"bin": { "my-server": "dist/index.js" }`)
|
|
62
|
+
|
|
63
|
+
The `bin` field is the most commonly missed one. Without it, `npx my-server` won't work — the client config must use `node dist/index.js` instead.
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# README.md Conventions for MCP Servers
|
|
2
|
+
|
|
3
|
+
Structure and content guide for creating or updating a README for an MCP server built on `@cyanheads/mcp-ts-core`. If a README already exists, use this as a reference to audit and improve it — don't blindly rewrite sections that are already accurate.
|
|
4
|
+
|
|
5
|
+
## Structure
|
|
6
|
+
|
|
7
|
+
Use this section order. Omit sections that don't apply (e.g., skip Docker if the server doesn't ship a container image).
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
# {Server Name}
|
|
11
|
+
|
|
12
|
+
One-line description of what the server does.
|
|
13
|
+
|
|
14
|
+
## Overview
|
|
15
|
+
## Features (tool/resource table)
|
|
16
|
+
## Installation
|
|
17
|
+
## Configuration
|
|
18
|
+
## Usage
|
|
19
|
+
## Docker (if Dockerfile present)
|
|
20
|
+
## Development
|
|
21
|
+
## License
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Section Guide
|
|
25
|
+
|
|
26
|
+
### Title + Description
|
|
27
|
+
|
|
28
|
+
The `h1` is the server name. Follow it with a single sentence or short paragraph explaining what the server wraps and who it's for. Include badges if publishing to npm.
|
|
29
|
+
|
|
30
|
+
```markdown
|
|
31
|
+
# my-mcp-server
|
|
32
|
+
|
|
33
|
+
MCP server for the Acme API — exposes project management, task tracking, and team operations to LLM clients.
|
|
34
|
+
|
|
35
|
+
[](https://www.npmjs.com/package/my-mcp-server)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Overview
|
|
39
|
+
|
|
40
|
+
2-4 sentences expanding on the description. What system does it wrap? What can the LLM do through it? What's the value proposition?
|
|
41
|
+
|
|
42
|
+
Avoid marketing language. State what it does, not why it's amazing.
|
|
43
|
+
|
|
44
|
+
### Features
|
|
45
|
+
|
|
46
|
+
A table of tools and resources is the most useful thing a README can provide. It tells both humans and LLMs exactly what the server exposes.
|
|
47
|
+
|
|
48
|
+
**Tools table:**
|
|
49
|
+
|
|
50
|
+
```markdown
|
|
51
|
+
### Tools
|
|
52
|
+
|
|
53
|
+
| Tool | Description | Key Inputs |
|
|
54
|
+
|:-----|:------------|:-----------|
|
|
55
|
+
| `search_projects` | Search projects by name or status | `query`, `status?` |
|
|
56
|
+
| `create_task` | Create a new task in a project | `projectId`, `title`, `description?` |
|
|
57
|
+
| `update_task` | Update task status or assignment | `taskId`, `status?`, `assignee?` |
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Resources table (if any):**
|
|
61
|
+
|
|
62
|
+
```markdown
|
|
63
|
+
### Resources
|
|
64
|
+
|
|
65
|
+
| URI Pattern | Description |
|
|
66
|
+
|:------------|:------------|
|
|
67
|
+
| `acme://projects/{projectId}` | Project details by ID |
|
|
68
|
+
| `acme://tasks/{taskId}` | Task details by ID |
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Prompts table (if any):**
|
|
72
|
+
|
|
73
|
+
```markdown
|
|
74
|
+
### Prompts
|
|
75
|
+
|
|
76
|
+
| Prompt | Description |
|
|
77
|
+
|:-------|:------------|
|
|
78
|
+
| `project_summary` | Summarize a project's status and open tasks |
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Derive these tables directly from the actual tool/resource/prompt definitions. Use the real names and descriptions from the Zod schemas.
|
|
82
|
+
|
|
83
|
+
### Installation
|
|
84
|
+
|
|
85
|
+
Show the install command and minimum viable configuration.
|
|
86
|
+
|
|
87
|
+
```markdown
|
|
88
|
+
## Installation
|
|
89
|
+
|
|
90
|
+
\`\`\`bash
|
|
91
|
+
npm install my-mcp-server
|
|
92
|
+
\`\`\`
|
|
93
|
+
|
|
94
|
+
### MCP Client Configuration
|
|
95
|
+
|
|
96
|
+
Add to your MCP client config (e.g., `claude_desktop_config.json`):
|
|
97
|
+
|
|
98
|
+
\`\`\`json
|
|
99
|
+
{
|
|
100
|
+
"mcpServers": {
|
|
101
|
+
"my-mcp-server": {
|
|
102
|
+
"command": "npx",
|
|
103
|
+
"args": ["my-mcp-server"],
|
|
104
|
+
"env": {
|
|
105
|
+
"ACME_API_KEY": "your-api-key"
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
\`\`\`
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
If the server supports HTTP transport, show that config too.
|
|
114
|
+
|
|
115
|
+
### Configuration
|
|
116
|
+
|
|
117
|
+
Table of environment variables. Include framework vars only if the server uses non-default values.
|
|
118
|
+
|
|
119
|
+
```markdown
|
|
120
|
+
## Configuration
|
|
121
|
+
|
|
122
|
+
| Variable | Required | Default | Description |
|
|
123
|
+
|:---------|:---------|:--------|:------------|
|
|
124
|
+
| `ACME_API_KEY` | Yes | — | API key for the Acme service |
|
|
125
|
+
| `ACME_BASE_URL` | No | `https://api.acme.com` | API base URL |
|
|
126
|
+
| `MCP_TRANSPORT_TYPE` | No | `stdio` | Transport: `stdio` or `http` |
|
|
127
|
+
| `MCP_LOG_LEVEL` | No | `info` | Log level |
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Source this from the server config Zod schema and `.env.example`.
|
|
131
|
+
|
|
132
|
+
### Usage
|
|
133
|
+
|
|
134
|
+
Brief examples of how an LLM (or human via MCP client) would use the server. Show 1-2 tool calls with example inputs/outputs if it helps understanding. Keep it short — the tool descriptions should be self-explanatory.
|
|
135
|
+
|
|
136
|
+
### Development
|
|
137
|
+
|
|
138
|
+
Commands table for contributors.
|
|
139
|
+
|
|
140
|
+
```markdown
|
|
141
|
+
## Development
|
|
142
|
+
|
|
143
|
+
| Command | Purpose |
|
|
144
|
+
|:--------|:--------|
|
|
145
|
+
| `npm run build` | Compile TypeScript |
|
|
146
|
+
| `npm run dev:stdio` | Dev mode (stdio, watch) |
|
|
147
|
+
| `npm run dev:http` | Dev mode (HTTP, watch) |
|
|
148
|
+
| `bun run devcheck` | Lint + format + typecheck |
|
|
149
|
+
| `npm test` | Run tests |
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Docker
|
|
153
|
+
|
|
154
|
+
Include only if a `Dockerfile` exists. Show how to build and run the image.
|
|
155
|
+
|
|
156
|
+
```markdown
|
|
157
|
+
## Docker
|
|
158
|
+
|
|
159
|
+
\`\`\`bash
|
|
160
|
+
docker build -t my-mcp-server .
|
|
161
|
+
docker run -p 3010:3010 -e MY_API_KEY=your-key my-mcp-server
|
|
162
|
+
\`\`\`
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Keep it minimal — the Dockerfile's defaults handle transport, port, and log config. Only document env vars the user must provide.
|
|
166
|
+
|
|
167
|
+
### License
|
|
168
|
+
|
|
169
|
+
One line referencing the LICENSE file.
|
|
170
|
+
|
|
171
|
+
```markdown
|
|
172
|
+
## License
|
|
173
|
+
|
|
174
|
+
Apache-2.0 — see [LICENSE](LICENSE) for details.
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Principles
|
|
178
|
+
|
|
179
|
+
- **Accuracy over aspiration.** Only document what exists. Don't describe planned features as if they're implemented.
|
|
180
|
+
- **Tables over prose** for structured data (tools, config, commands). Scannable and diff-friendly.
|
|
181
|
+
- **Real names from code.** Tool names, env vars, and URIs should match the source exactly. Copy from the definitions, don't paraphrase.
|
|
182
|
+
- **No badges unless publishing.** Badges for unpublished packages are noise.
|
|
183
|
+
- **Keep it current.** The README should be updated whenever tools are added or removed. The `polish-docs-meta` skill handles both initial creation and subsequent updates.
|