@cyanheads/mcp-ts-core 0.13.0 → 0.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +13 -3
- package/CLAUDE.md +13 -3
- package/README.md +1 -1
- package/changelog/0.13.x/0.13.1.md +56 -0
- package/{tsconfig.base.json → config/tsconfig.base.json} +2 -2
- package/dist/config/index.d.ts +8 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +8 -0
- package/dist/config/index.js.map +1 -1
- package/dist/core/app.d.ts +82 -2
- package/dist/core/app.d.ts.map +1 -1
- package/dist/core/app.js +129 -6
- package/dist/core/app.js.map +1 -1
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/worker.d.ts +6 -1
- package/dist/core/worker.d.ts.map +1 -1
- package/dist/core/worker.js.map +1 -1
- package/dist/linter/rules/resource-rules.js +9 -2
- package/dist/linter/rules/resource-rules.js.map +1 -1
- package/dist/linter/rules/tool-rules.js +4 -1
- package/dist/linter/rules/tool-rules.js.map +1 -1
- package/dist/mcp-server/types.d.ts +10 -3
- package/dist/mcp-server/types.d.ts.map +1 -1
- package/dist/mcp-server/types.js +4 -3
- package/dist/mcp-server/types.js.map +1 -1
- package/dist/services/canvas/core/sqlGate.d.ts.map +1 -1
- package/dist/services/canvas/core/sqlGate.js +27 -2
- package/dist/services/canvas/core/sqlGate.js.map +1 -1
- package/dist/utils/pagination/pagination.d.ts.map +1 -1
- package/dist/utils/pagination/pagination.js +4 -1
- package/dist/utils/pagination/pagination.js.map +1 -1
- package/dist/utils/parsing/frontmatterParser.d.ts +8 -7
- package/dist/utils/parsing/frontmatterParser.d.ts.map +1 -1
- package/dist/utils/parsing/frontmatterParser.js +91 -16
- package/dist/utils/parsing/frontmatterParser.js.map +1 -1
- package/framework-skills/add-tool/SKILL.md +2 -2
- package/framework-skills/api-config/SKILL.md +19 -3
- package/framework-skills/api-context/SKILL.md +3 -1
- package/framework-skills/api-telemetry/SKILL.md +13 -10
- package/framework-skills/code-simplifier/SKILL.md +12 -6
- package/framework-skills/design-mcp-server/SKILL.md +2 -2
- package/framework-skills/maintenance/SKILL.md +2 -2
- package/framework-skills/polish-docs-meta/SKILL.md +1 -1
- package/framework-skills/polish-docs-meta/references/readme.md +12 -8
- package/framework-skills/release-and-publish/SKILL.md +12 -3
- package/framework-skills/report-issue-framework/SKILL.md +2 -1
- package/framework-skills/report-issue-local/SKILL.md +7 -1
- package/package.json +6 -6
- package/scripts/build.ts +2 -2
- package/scripts/devcheck.ts +2 -2
- package/templates/.env.example +5 -2
- package/templates/AGENTS.md +16 -0
- package/templates/CLAUDE.md +16 -0
- package/templates/src/index.ts +10 -0
|
@@ -123,18 +123,22 @@ If a public hosted instance is available, **promote it to a top-level callout**
|
|
|
123
123
|
|
|
124
124
|
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.
|
|
125
125
|
|
|
126
|
+
No hosted instance → omit the callout, the Getting Started subsection, and any hosted mention in the Overview. Never state the absence ("no public hosted instance"); self-hosting is the default a reader already assumes.
|
|
127
|
+
|
|
126
128
|
### Overview
|
|
127
129
|
|
|
128
130
|
The first section after the header rule. Two parts: a short description paragraph, then one two-column table per primitive type. This is what a visitor reads to decide whether the server is for them, so it must scan in one screen.
|
|
129
131
|
|
|
130
|
-
**Description paragraph:** two or three sentences — what the server sits on top of (the upstream APIs), what a user can do with it (the headline workflows, action verbs), and how it runs (transports, the hosted endpoint
|
|
132
|
+
**Description paragraph:** two or three sentences — what the server sits on top of (the upstream APIs), what a user can do with it (the headline workflows, action verbs), and how it runs (transports, plus the hosted endpoint when one exists). Not a count.
|
|
133
|
+
|
|
134
|
+
The opening sentence names the subject, not the container. The reader is already on an MCP server's repo page — the `<h1>`, the badge row, and the framework line all say so — so an opener that restates it ("An MCP server over…", "An MCP calculator…", "An MCP server that…") spends the most-read sentence on nothing. Lead with the domain or the upstream as a noun phrase, article optional: "Calculator powered by math.js.", "Seismic data from USGS ComCat and the EMSC SeismicPortal.", "The Acme v2 API — projects, tasks, and team activity.", "Read, write, and search Obsidian vault notes over the Local REST API plugin." The words "MCP server" appear at most once in the paragraph, and never as its first noun.
|
|
131
135
|
|
|
132
136
|
**Primitive tables:** a `### Tools` table, then `### Resources` and `### Prompts` tables when the server has any. Omit a heading whose table would be empty, but keep a one-row table rather than folding it into another. Two columns, Name/Description, one-line descriptions — the detail lives in the Capability reference.
|
|
133
137
|
|
|
134
138
|
```markdown
|
|
135
139
|
## Overview
|
|
136
140
|
|
|
137
|
-
|
|
141
|
+
Project management over the Acme v2 API. Search projects, manage tasks, and track team activity from any MCP client. Runs as a stdio process, a local Streamable HTTP server, or the public hosted endpoint above.
|
|
138
142
|
|
|
139
143
|
### Tools
|
|
140
144
|
|
|
@@ -201,12 +205,12 @@ Link an examples file from an entry when one exists: `[View detailed examples](.
|
|
|
201
205
|
|
|
202
206
|
### Features
|
|
203
207
|
|
|
204
|
-
|
|
208
|
+
The framework line below, verbatim — it names what a user gets from the framework (transports, auth, storage, observability), so it replaces any framework-feature bullets; contributor facts about code organization belong in the Development guide. Then two labeled bullet groups, both always present: `<Upstream>-specific:` (3–5 bullets on the server's own integration), then `Agent-friendly output:`.
|
|
205
209
|
|
|
206
210
|
```markdown
|
|
207
211
|
## Features
|
|
208
212
|
|
|
209
|
-
Built on [`@cyanheads/mcp-ts-core`](https://
|
|
213
|
+
Built on [`@cyanheads/mcp-ts-core`](https://github.com/cyanheads/mcp-ts-core): stdio and Streamable HTTP transports, pluggable auth (`none` / `jwt` / `oauth`), swappable storage (`in-memory`, `filesystem`, `Supabase`, `Cloudflare KV/R2/D1`), structured logging with optional OpenTelemetry tracing.
|
|
210
214
|
|
|
211
215
|
Acme-specific:
|
|
212
216
|
|
|
@@ -221,7 +225,7 @@ Agent-friendly output:
|
|
|
221
225
|
- Discriminated output contracts — typed status and source fields let callers branch on data, not string parsing
|
|
222
226
|
```
|
|
223
227
|
|
|
224
|
-
The **Agent-friendly output** subsection documents output-design choices that make the server work well as an AI-agent backend.
|
|
228
|
+
The **Agent-friendly output** subsection documents output-design choices that make the server work well as an AI-agent backend. Always include it, with 2–4 bullets in the "Pattern — concrete detail" form, each naming fields or behavior verified in the server's source — not aspirational framework capabilities. Drop a pattern the server doesn't have (no batch tools → no partial-failure bullet) rather than claiming it. Examples of what fits:
|
|
225
229
|
|
|
226
230
|
- Provenance: source labels (`viaSource`, `source`), license/access-level fields, effective-query echo, best-effort warnings on lossy tiers
|
|
227
231
|
- Partial failure: per-item status in batch operations, structured error rows alongside successes, recovery hints ("Next Step" text)
|
|
@@ -434,10 +438,10 @@ The Dockerfile defaults to HTTP transport, stateless session mode, and logs to `
|
|
|
434
438
|
|
|
435
439
|
### Cloudflare Workers
|
|
436
440
|
|
|
437
|
-
1. **
|
|
441
|
+
1. **Run locally under wrangler:**
|
|
438
442
|
|
|
439
443
|
\`\`\`sh
|
|
440
|
-
bun run
|
|
444
|
+
bun run deploy:dev
|
|
441
445
|
\`\`\`
|
|
442
446
|
|
|
443
447
|
2. **Deploy:**
|
|
@@ -447,7 +451,7 @@ bun run deploy:prod
|
|
|
447
451
|
\`\`\`
|
|
448
452
|
```
|
|
449
453
|
|
|
450
|
-
Include the Docker
|
|
454
|
+
Include the Docker subsection only if the server ships a Dockerfile, and the Workers subsection only if it ships a `src/worker.ts` entry. The Docker trailing paragraph (log directory, OTEL build arg) is important — it documents Dockerfile behavior that isn't obvious from the build command.
|
|
451
455
|
|
|
452
456
|
### Project Structure
|
|
453
457
|
|
|
@@ -4,7 +4,7 @@ description: >
|
|
|
4
4
|
Ship a release end-to-end across every registry the project targets (npm, MCP Registry, GitHub Releases for `.mcpb` bundles, GHCR). Runs the final verification gate, fast-forwards `main` when the release rode a release PR, creates the annotated tag on the commit `main` now points at, pushes commits and tags, then publishes to each applicable destination. Assumes git wrapup (version bumps, changelog, commit stack — and in release PR mode, the pushed branch and open PR) is already complete — this skill is the post-wrapup merge + tag + publish workflow. Retries transient network failures on publish steps; halts with a partial-state report when retries are exhausted or the failure is terminal.
|
|
5
5
|
metadata:
|
|
6
6
|
author: cyanheads
|
|
7
|
-
version: "2.
|
|
7
|
+
version: "2.17"
|
|
8
8
|
audience: external
|
|
9
9
|
type: workflow
|
|
10
10
|
---
|
|
@@ -111,12 +111,15 @@ If `--ff-only` refuses, `main` moved underneath the release branch. Halt and rep
|
|
|
111
111
|
The tag goes on HEAD. In release PR mode that is `main`'s tip after step 3 — the commit the PR's `headRefOid` names — so the tag is created on the branch it stays reachable from.
|
|
112
112
|
|
|
113
113
|
```bash
|
|
114
|
-
|
|
114
|
+
cat > /tmp/tag-v<version>.md <<'TAG'
|
|
115
|
+
<tag message>
|
|
116
|
+
TAG
|
|
117
|
+
git tag -a v<version> --cleanup=whitespace -F /tmp/tag-v<version>.md
|
|
115
118
|
```
|
|
116
119
|
|
|
117
120
|
If `v<version>` already exists and points at HEAD, a prior run created it — proceed. If it exists and points anywhere else, **halt and report the conflict** with the version string, the existing tag SHA, and HEAD. Never delete or move a tag without explicit authorization.
|
|
118
121
|
|
|
119
|
-
|
|
122
|
+
Write the message to a file through a quoted-delimiter heredoc and pass it with `-F`, never inline with `-m`: the body carries backticks, which a double-quoted string runs as command substitution and silently deletes, and apostrophes, which end a single-quoted string. The tag message renders as the GitHub Release body via `--notes-from-tag`. It must be structured markdown, not a flat string.
|
|
120
123
|
|
|
121
124
|
**Release PR mode: the tag body is the PR body's `## Changes` bullets plus its final changelog link, verbatim** — `gh pr view <N> --json body -q .body` (`<N>` from step 1 — on `main` there is no branch for `gh` to infer it from), take the theme line as the subject, the bullets under `## Changes`, and the last line; drop `## Gates` and the headers. That digest was authored at wrapup and reviewed on the PR; re-authoring it here would publish unreviewed words. The one addition: append ` · release PR #<N>` to that final line, so the GitHub Release points at its audit trail (GitHub autolinks the bare `#<N>`). Without a PR, author it from the changelog entry at `changelog/<major.minor>.x/<version>.md` — every claim in the tag must appear in that file, and the file's `summary:` line is the tag's theme.
|
|
122
125
|
|
|
@@ -193,10 +196,16 @@ Halt on publish error other than "version already exists" (which means this step
|
|
|
193
196
|
|
|
194
197
|
Only if `server.json` exists at the repo root (otherwise skip). Note: `server.json` (MCP Registry metadata) and `manifest.json` (MCPB bundle manifest, step 8) are independent — a project may have either, both, or neither.
|
|
195
198
|
|
|
199
|
+
The registry checks that the npm version exists before it registers, and npm's read endpoint can lag `bun publish` by several minutes. Wait for the version to be served before publishing; a publisher error saying the npm version was not found is this lag, not a terminal failure:
|
|
200
|
+
|
|
196
201
|
```bash
|
|
202
|
+
curl -sf --retry 30 --retry-delay 30 --retry-all-errors -o /dev/null \
|
|
203
|
+
"https://registry.npmjs.org/<package-name>/<version>"
|
|
197
204
|
bun run publish-mcp
|
|
198
205
|
```
|
|
199
206
|
|
|
207
|
+
Step 8 depends only on the pushed tag, so it may run while this wait is in progress.
|
|
208
|
+
|
|
200
209
|
If `publish-mcp` isn't defined in `package.json`, add it permanently (one-time setup, macOS):
|
|
201
210
|
|
|
202
211
|
```json
|
|
@@ -4,7 +4,7 @@ description: >
|
|
|
4
4
|
File a bug or feature request against @cyanheads/mcp-ts-core when you hit a framework issue. Use when a builder, utility, context method, or config behaves contrary to the documented API — not for server-specific application bugs.
|
|
5
5
|
metadata:
|
|
6
6
|
author: cyanheads
|
|
7
|
-
version: "1.
|
|
7
|
+
version: "1.11"
|
|
8
8
|
audience: external
|
|
9
9
|
type: workflow
|
|
10
10
|
---
|
|
@@ -181,6 +181,7 @@ Every issue needs exactly one primary label. Stack secondary labels on top when
|
|
|
181
181
|
| `performance` | Memory, CPU, latency, or resource usage |
|
|
182
182
|
| `security` | Vulnerability, CVE, or hardening work |
|
|
183
183
|
| `breaking-change` | Fix/feature will break public API; requires a major bump |
|
|
184
|
+
| `blocked-by-sdk` | Fix requires changes in `@modelcontextprotocol/sdk` |
|
|
184
185
|
| `surplus-token-idea` | Worth exploring when token budget allows |
|
|
185
186
|
|
|
186
187
|
Combine labels: `--label "bug" --label "regression"`.
|
|
@@ -4,7 +4,7 @@ description: >
|
|
|
4
4
|
File a bug or feature request against this MCP server's own repo. Use for server-specific issues — tool logic, service integrations, config problems, or domain bugs that aren't caused by the framework.
|
|
5
5
|
metadata:
|
|
6
6
|
author: cyanheads
|
|
7
|
-
version: "1.
|
|
7
|
+
version: "1.9"
|
|
8
8
|
audience: external
|
|
9
9
|
type: workflow
|
|
10
10
|
---
|
|
@@ -165,8 +165,12 @@ Every issue needs exactly one primary label. Stack secondary labels on top when
|
|
|
165
165
|
| `performance` | Memory, CPU, latency, or resource usage |
|
|
166
166
|
| `security` | Vulnerability, CVE, or hardening work |
|
|
167
167
|
| `breaking-change` | Change will break public API; requires a major bump |
|
|
168
|
+
| `blocked-by-framework` | Fix requires a released change in `@cyanheads/mcp-ts-core`; pairs with a `Depends on: cyanheads/mcp-ts-core#N` line in the body |
|
|
169
|
+
| `blocked-by-sdk` | Fix requires changes in `@modelcontextprotocol/sdk` |
|
|
168
170
|
| `surplus-token-idea` | Worth exploring when token budget allows |
|
|
169
171
|
|
|
172
|
+
`blocked-by-framework` comes off when this server adopts the release that ships the fix. An issue blocked on the SDK *through* the framework takes `blocked-by-framework`, not `blocked-by-sdk` — the server's own unblock is still a framework release.
|
|
173
|
+
|
|
170
174
|
Combine labels: `--label "bug" --label "regression"`.
|
|
171
175
|
|
|
172
176
|
Secondary labels are not GitHub defaults — if `gh issue create --label "regression"` fails with `label not found`, create it once:
|
|
@@ -176,6 +180,8 @@ gh label create regression --color e99695 --description "Worked before, broken a
|
|
|
176
180
|
gh label create performance --color 5319e7 --description "Memory, CPU, latency, or resource usage"
|
|
177
181
|
gh label create security --color b60205 --description "Vulnerability, CVE, or hardening work"
|
|
178
182
|
gh label create breaking-change --color d93f0b --description "Change will break public API; requires a major bump"
|
|
183
|
+
gh label create blocked-by-framework --color fbca04 --description "Fix requires a released change in @cyanheads/mcp-ts-core"
|
|
184
|
+
gh label create blocked-by-sdk --color c5def5 --description "Fix requires changes in @modelcontextprotocol/sdk"
|
|
179
185
|
gh label create surplus-token-idea --color FF10F0 --description "Worth exploring when token budget allows"
|
|
180
186
|
```
|
|
181
187
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyanheads/mcp-ts-core",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.1",
|
|
4
4
|
"mcpName": "io.github.cyanheads/mcp-ts-core",
|
|
5
5
|
"description": "Agent-native TypeScript framework for MCP servers. Includes runtime infrastructure and agent skills for building, testing, and shipping servers.",
|
|
6
6
|
"files": [
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"templates/",
|
|
26
26
|
"AGENTS.md",
|
|
27
27
|
"CLAUDE.md",
|
|
28
|
-
"tsconfig.base.json",
|
|
28
|
+
"config/tsconfig.base.json",
|
|
29
29
|
"vitest.config.base.mjs",
|
|
30
30
|
"biome.json"
|
|
31
31
|
],
|
|
@@ -123,7 +123,7 @@
|
|
|
123
123
|
"import": "./dist/testing/vitest.js",
|
|
124
124
|
"default": "./dist/testing/vitest.js"
|
|
125
125
|
},
|
|
126
|
-
"./tsconfig.base.json": "./tsconfig.base.json",
|
|
126
|
+
"./tsconfig.base.json": "./config/tsconfig.base.json",
|
|
127
127
|
"./vitest.config": "./vitest.config.base.mjs",
|
|
128
128
|
"./biome": "./biome.json",
|
|
129
129
|
"./package.json": "./package.json"
|
|
@@ -163,8 +163,8 @@
|
|
|
163
163
|
"format": "biome check --write .",
|
|
164
164
|
"format:unsafe": "biome check --write --unsafe .",
|
|
165
165
|
"typecheck": "bunx tsc --noEmit",
|
|
166
|
-
"typecheck:scripts": "bunx tsc --project tsconfig.scripts.json --noEmit",
|
|
167
|
-
"typecheck:worker": "bunx tsc --project tsconfig.worker.json --noEmit",
|
|
166
|
+
"typecheck:scripts": "bunx tsc --project config/tsconfig.scripts.json --noEmit",
|
|
167
|
+
"typecheck:worker": "bunx tsc --project config/tsconfig.worker.json --noEmit",
|
|
168
168
|
"list-skills": "bun run scripts/list-skills.ts",
|
|
169
169
|
"tree": "bun run scripts/tree.ts",
|
|
170
170
|
"fetch-spec": "bun run scripts/fetch-openapi-spec.ts",
|
|
@@ -234,7 +234,7 @@
|
|
|
234
234
|
"js-yaml": "^5.4.1",
|
|
235
235
|
"linkedom": "^0.18.13",
|
|
236
236
|
"node-cron": "^4.6.0",
|
|
237
|
-
"openai": "^7.
|
|
237
|
+
"openai": "^7.15.0",
|
|
238
238
|
"papaparse": "^5.7.0",
|
|
239
239
|
"partial-json": "^0.1.7",
|
|
240
240
|
"pdf-lib": "^1.17.1",
|
package/scripts/build.ts
CHANGED
|
@@ -95,8 +95,8 @@ async function main() {
|
|
|
95
95
|
const projectIdx = process.argv.indexOf('--project');
|
|
96
96
|
const project =
|
|
97
97
|
projectIdx !== -1
|
|
98
|
-
? (process.argv[projectIdx + 1] ?? 'tsconfig.build.json')
|
|
99
|
-
: 'tsconfig.build.json';
|
|
98
|
+
? (process.argv[projectIdx + 1] ?? 'config/tsconfig.build.json')
|
|
99
|
+
: 'config/tsconfig.build.json';
|
|
100
100
|
|
|
101
101
|
console.log(`\x1b[1mBuilding ${pkg.name}@${pkg.version}\x1b[0m`);
|
|
102
102
|
console.log(`\x1b[2m tsconfig: ${project}\x1b[0m`);
|
package/scripts/devcheck.ts
CHANGED
|
@@ -866,12 +866,12 @@ const ALL_CHECKS: Check[] = [
|
|
|
866
866
|
// globals cannot share one with @types/node's (#397). It reads the built
|
|
867
867
|
// declarations, so it only has something to check after a build.
|
|
868
868
|
getCommand: (ctx) => {
|
|
869
|
-
if (!existsSync(path.join(ctx.rootDir, 'tsconfig.worker.json'))) return null;
|
|
869
|
+
if (!existsSync(path.join(ctx.rootDir, 'config', 'tsconfig.worker.json'))) return null;
|
|
870
870
|
if (!existsSync(path.join(ctx.rootDir, 'dist'))) return null;
|
|
871
871
|
return [
|
|
872
872
|
path.join(ctx.rootDir, 'node_modules', '.bin', 'tsc'),
|
|
873
873
|
'--project',
|
|
874
|
-
'tsconfig.worker.json',
|
|
874
|
+
'config/tsconfig.worker.json',
|
|
875
875
|
'--noEmit',
|
|
876
876
|
];
|
|
877
877
|
},
|
package/templates/.env.example
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# ── Transport ──────────────────────────────────────────────────────────
|
|
2
2
|
# MCP_TRANSPORT_TYPE=stdio # stdio | http (default: stdio)
|
|
3
3
|
# MCP_HTTP_PORT=3010 # HTTP port (default: 3010)
|
|
4
|
-
# MCP_HTTP_HOST=
|
|
4
|
+
# MCP_HTTP_HOST=127.0.0.1 # HTTP host (default: 127.0.0.1)
|
|
5
5
|
# MCP_HTTP_ENDPOINT_PATH=/mcp # HTTP endpoint path (default: /mcp)
|
|
6
6
|
# MCP_HTTP_MAX_BODY_BYTES=1048576 # Max request body bytes; 413 over limit, 0 disables (default: 1048576)
|
|
7
7
|
# MCP_PUBLIC_URL= # Public origin behind a TLS-terminating proxy (e.g. https://mcp.example.com)
|
|
@@ -14,7 +14,10 @@
|
|
|
14
14
|
# STORAGE_PROVIDER_TYPE=in-memory # in-memory | filesystem | supabase | cloudflare-r2 | cloudflare-kv | cloudflare-d1
|
|
15
15
|
|
|
16
16
|
# ── Session ──────────────────────────────────────────────────────────
|
|
17
|
-
|
|
17
|
+
MCP_SESSION_MODE=stateless # stateful | stateless | auto. Set here, not left to the schema default
|
|
18
|
+
# (auto, which resolves to stateful). Stateless fits a data API:
|
|
19
|
+
# no session store, horizontally scalable. Use stateful when a tool
|
|
20
|
+
# asks the caller for input mid-handler (ctx.requestInput).
|
|
18
21
|
# MCP_HTTP_RESUMABILITY=false # SSE replay on a dropped stateful stream. Default: true.
|
|
19
22
|
# Kill switch only — no effect on stateless serving.
|
|
20
23
|
# MCP_HTTP_RESUMABILITY_MAX_EVENTS=512 # Retained per session, oldest evicted first
|
package/templates/AGENTS.md
CHANGED
|
@@ -174,6 +174,22 @@ await createApp({
|
|
|
174
174
|
|
|
175
175
|
`instructions` is optional server-level orientation, sent on every `initialize` as session-level context. Use it for deployment guidance (connection aliases, regional notes, scope hints) instead of repeating the same context across tool descriptions. Client adoption is uneven, but there's no downside when set.
|
|
176
176
|
|
|
177
|
+
### Session posture and shutdown
|
|
178
|
+
|
|
179
|
+
Two more `createApp()` options shape how the server runs rather than how it presents itself:
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
await createApp({
|
|
183
|
+
sessionMode: 'stateless', // or { default: 'stateful', require: 'stateful' }
|
|
184
|
+
setup(core) { startMyWatcher(core.config); },
|
|
185
|
+
async teardown() { await stopMyWatcher(); },
|
|
186
|
+
});
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
`sessionMode` declares the HTTP session posture in `src/` instead of leaving it to a deployment's `MCP_SESSION_MODE`, which still wins whenever it carries a meaningful value (an empty string and an unsubstituted `${…}` placeholder read as unset and fall through to the option). Add `require: 'stateful'` when a tool asks the caller for input mid-handler via `ctx.requestInput`: startup then fails with a `ConfigurationError` rather than serving a mode in which a 2025-era client can never answer the prompt. Stdio is never refused.
|
|
190
|
+
|
|
191
|
+
`teardown(core)` is the `setup()` counterpart — release a watcher, socket, or non-`unref()`'d timer there. It runs after the transport stops and before the logger closes, on every shutdown path, and a signal-triggered shutdown then exits the process explicitly (0, or 1 if a step never settles within the framework's 10 s ceiling).
|
|
192
|
+
|
|
177
193
|
---
|
|
178
194
|
|
|
179
195
|
## Context
|
package/templates/CLAUDE.md
CHANGED
|
@@ -174,6 +174,22 @@ await createApp({
|
|
|
174
174
|
|
|
175
175
|
`instructions` is optional server-level orientation, sent on every `initialize` as session-level context. Use it for deployment guidance (connection aliases, regional notes, scope hints) instead of repeating the same context across tool descriptions. Client adoption is uneven, but there's no downside when set.
|
|
176
176
|
|
|
177
|
+
### Session posture and shutdown
|
|
178
|
+
|
|
179
|
+
Two more `createApp()` options shape how the server runs rather than how it presents itself:
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
await createApp({
|
|
183
|
+
sessionMode: 'stateless', // or { default: 'stateful', require: 'stateful' }
|
|
184
|
+
setup(core) { startMyWatcher(core.config); },
|
|
185
|
+
async teardown() { await stopMyWatcher(); },
|
|
186
|
+
});
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
`sessionMode` declares the HTTP session posture in `src/` instead of leaving it to a deployment's `MCP_SESSION_MODE`, which still wins whenever it carries a meaningful value (an empty string and an unsubstituted `${…}` placeholder read as unset and fall through to the option). Add `require: 'stateful'` when a tool asks the caller for input mid-handler via `ctx.requestInput`: startup then fails with a `ConfigurationError` rather than serving a mode in which a 2025-era client can never answer the prompt. Stdio is never refused.
|
|
190
|
+
|
|
191
|
+
`teardown(core)` is the `setup()` counterpart — release a watcher, socket, or non-`unref()`'d timer there. It runs after the transport stops and before the logger closes, on every shutdown path, and a signal-triggered shutdown then exits the process explicitly (0, or 1 if a step never settles within the framework's 10 s ceiling).
|
|
192
|
+
|
|
177
193
|
---
|
|
178
194
|
|
|
179
195
|
## Context
|
package/templates/src/index.ts
CHANGED
|
@@ -20,4 +20,14 @@ await createApp({
|
|
|
20
20
|
// instructions: 'Server-level orientation forwarded to the model on every initialize.\n' +
|
|
21
21
|
// '- Use shortcut `X` for the most common case\n' +
|
|
22
22
|
// '- Tools require auth via the `inventory:read` scope',
|
|
23
|
+
|
|
24
|
+
// Session posture in code rather than in a Dockerfile. MCP_SESSION_MODE still
|
|
25
|
+
// wins when it is set. Add `require: 'stateful'` — `{ default: 'stateful',
|
|
26
|
+
// require: 'stateful' }` — when a tool asks the caller for input mid-handler,
|
|
27
|
+
// so a stateless deployment fails at startup instead of losing that tool.
|
|
28
|
+
// sessionMode: 'stateless',
|
|
29
|
+
|
|
30
|
+
// Release what setup() allocated: a watcher, a socket, a timer the framework
|
|
31
|
+
// cannot see. Runs after the transport stops and before the logger closes.
|
|
32
|
+
// teardown(core) { core.logger.info('bye', { requestId: 'shutdown', timestamp: new Date().toISOString() }); },
|
|
23
33
|
});
|