@vantageos/mcp-boilerplate 0.1.0 → 0.1.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-plugin/plugin.json +15 -2
- package/CHANGELOG.md +67 -0
- package/README.fr.md +193 -0
- package/README.md +11 -9
- package/dist/mcpServerFactory.js +21 -2
- package/dist/stdio.js +8 -1
- package/dist/ui-bundle/widget.html +13 -14
- package/package.json +5 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vantage-mcp-boilerplate",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Clonable dual-transport MCP server template (stdio + Streamable HTTP, stateless) on the official @modelcontextprotocol/sdk, with protocol-kit result types, OAuth 2.1 auth + public tier, multi-tenant JWT scoping, MCP Apps UI extension, server-side FR/EN i18n, and a declarative eval harness. Scaffold, extend, publish.",
|
|
5
5
|
"description_fr": "Template de serveur MCP clonable a double transport (stdio + Streamable HTTP, stateless) sur le @modelcontextprotocol/sdk officiel, avec types de resultats protocol-kit, auth OAuth 2.1 + tier public, scoping multi-tenant par JWT, extension UI MCP Apps, i18n FR/EN cote serveur, et un harnais d'evaluations declaratif. Scaffolder, etendre, publier.",
|
|
6
6
|
"author": "ElPi Corp / Laurent Perello",
|
|
@@ -8,5 +8,18 @@
|
|
|
8
8
|
"homepage": "https://github.com/elpiarthera/vantage-mcp-boilerplate",
|
|
9
9
|
"category": "mcp-server",
|
|
10
10
|
"bilingual": true,
|
|
11
|
-
"keywords": [
|
|
11
|
+
"keywords": [
|
|
12
|
+
"mcp",
|
|
13
|
+
"claude-code",
|
|
14
|
+
"boilerplate",
|
|
15
|
+
"starter",
|
|
16
|
+
"template",
|
|
17
|
+
"stdio",
|
|
18
|
+
"streamable-http",
|
|
19
|
+
"oauth",
|
|
20
|
+
"multi-tenant",
|
|
21
|
+
"i18n",
|
|
22
|
+
"vantage",
|
|
23
|
+
"elpi"
|
|
24
|
+
]
|
|
12
25
|
}
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@vantageos/mcp-boilerplate` are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.2] - 2026-08-07
|
|
11
|
+
|
|
12
|
+
Two derive-never-type fixes, released together.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- `tools/list` gating bug: the response was a hand-typed 2-entry descriptor
|
|
17
|
+
array (`ping`, `list_items`) while a third tool, `render_items_ui` (MCP
|
|
18
|
+
Apps UI), was registered on the server — callable but undiscoverable via
|
|
19
|
+
`tools/list`. The handler now derives the response from the SDK's own
|
|
20
|
+
registered-tools map, so no tool can be silently missing from discovery
|
|
21
|
+
again.
|
|
22
|
+
- `.claude-plugin/plugin.json`'s `version` field had drifted from
|
|
23
|
+
`package.json` (0.1.0 vs 0.1.1). It is now derived from `package.json` at
|
|
24
|
+
build time (`scripts/sync-plugin-version.mjs`, wired into `npm run build`).
|
|
25
|
+
|
|
26
|
+
## [0.1.1] - 2026-08-07
|
|
27
|
+
|
|
28
|
+
Hardening pass on the published template — packaging and documentation
|
|
29
|
+
hygiene, no behavioral changes to the server layers.
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- Bilingual `README.fr.md` + `description_fr` in `package.json` (T1).
|
|
34
|
+
- This `CHANGELOG.md`, shipped inside the npm package (T2).
|
|
35
|
+
- Eval suite hardened to >=3 evals/tool, with an opt-in tenant toggle (T3).
|
|
36
|
+
- Fleet `biome.json` shipped at source, normalized to 0 lint errors (from #2).
|
|
37
|
+
|
|
38
|
+
### Changed
|
|
39
|
+
|
|
40
|
+
- Template hygiene: `mosaic-card` vendored into the template instead of an
|
|
41
|
+
external dependency; alpha-only devDependency dropped (T4).
|
|
42
|
+
|
|
43
|
+
## [0.1.0] - 2026-08-04
|
|
44
|
+
|
|
45
|
+
Initial published release.
|
|
46
|
+
|
|
47
|
+
### Added
|
|
48
|
+
|
|
49
|
+
- Dual-transport MCP server bootstrap built exclusively on the official
|
|
50
|
+
`@modelcontextprotocol/sdk` transports: stdio (`StdioServerTransport`) and
|
|
51
|
+
stateless Streamable HTTP (`WebStandardStreamableHTTPServerTransport`).
|
|
52
|
+
- `@vantageos/mcp-protocol-kit` wiring for shared result types.
|
|
53
|
+
- OAuth 2.1 resource-server auth layer (`@vantageos/mcp-auth-kit`), with a
|
|
54
|
+
public no-auth tier alongside the authenticated tier.
|
|
55
|
+
- Multi-tenant scoping layer with proven tenant isolation.
|
|
56
|
+
- MCP Apps UI extension: `ui://` resource serving a bundled widget
|
|
57
|
+
(`src/ui/Widget.tsx`, Vite single-file build).
|
|
58
|
+
- Bilingual i18n (FR/EN) via `@vantageos/mosaic-i18n`, covering tool
|
|
59
|
+
descriptions and the UI resource.
|
|
60
|
+
- Evals harness (`evals/`) exercising the tool surface end-to-end.
|
|
61
|
+
- Example `ping` tool proving the handshake on both transports.
|
|
62
|
+
- Reproducible build via `npm ci`; 52/52 tests passing at release time.
|
|
63
|
+
- MIT license, clonable as a starter template.
|
|
64
|
+
|
|
65
|
+
[Unreleased]: https://github.com/elpiarthera/vantage-mcp-boilerplate/compare/v0.1.1...HEAD
|
|
66
|
+
[0.1.1]: https://github.com/elpiarthera/vantage-mcp-boilerplate/compare/v0.1.0...v0.1.1
|
|
67
|
+
[0.1.0]: https://github.com/elpiarthera/vantage-mcp-boilerplate/releases/tag/v0.1.0
|
package/README.fr.md
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# @vantageos/mcp-boilerplate
|
|
2
|
+
|
|
3
|
+
Un squelette de serveur MCP clonable : bootstrap double-transport (stdio +
|
|
4
|
+
Streamable HTTP, sans état) construit exclusivement sur les transports
|
|
5
|
+
officiels du [`@modelcontextprotocol/sdk`](https://www.npmjs.com/package/@modelcontextprotocol/sdk).
|
|
6
|
+
Aucune route REST personnalisée ne se place jamais devant un appel d'outil.
|
|
7
|
+
|
|
8
|
+
Ceci est une fondation, pas un produit fini : il embarque un outil d'exemple
|
|
9
|
+
trivial (`ping`) dont le seul but est de prouver que la poignée de main MCP
|
|
10
|
+
fonctionne sur les deux transports. Les couches ultérieures (types de résultat
|
|
11
|
+
protocol-kit, authentification, scoping multi-tenant, extensions UI, i18n) se
|
|
12
|
+
construisent au-dessus de ce bootstrap sans modifier le câblage du transport.
|
|
13
|
+
|
|
14
|
+
## Structure
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
src/
|
|
18
|
+
mcpServerFactory.ts # définition unique du serveur MCP, partagée par les deux transports
|
|
19
|
+
stdio.ts # point d'entrée StdioServerTransport du SDK officiel
|
|
20
|
+
http.ts # adaptateur Node http.Server autour de l'app Hono
|
|
21
|
+
httpApp.ts # WebStandardStreamableHTTPServerTransport du SDK officiel (sans état)
|
|
22
|
+
auth.ts # câblage OAuth 2.1 resource-server (@vantageos/mcp-auth-kit)
|
|
23
|
+
config.ts # chargeurs AuthMode + AuthConfig dérivés de l'environnement
|
|
24
|
+
index.ts # exports du package
|
|
25
|
+
tests/
|
|
26
|
+
helpers/mcpRpc.ts # helpers de requête JSON-RPC pour le transport HTTP
|
|
27
|
+
helpers/authFixtures.ts # fixtures de signature JWT RS256 réservées aux tests
|
|
28
|
+
httpHandshake.test.ts # initialize -> tools/list -> tools/call sur Streamable HTTP
|
|
29
|
+
stdioHandshake.test.ts # même poignée de main sur un vrai process enfant stdio
|
|
30
|
+
oauth.test.ts # les deux paliers d'authentification : gate oauth + palier public sans auth
|
|
31
|
+
docs/
|
|
32
|
+
architecture.md # posture du protocole : version au niveau outil vs au niveau transport
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Démarrage rapide
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm install
|
|
39
|
+
npm run build
|
|
40
|
+
|
|
41
|
+
# stdio (config client local, ex. Claude Code / Cursor) — jamais gardé,
|
|
42
|
+
# le process local qui invoque stdio EST l'appelant.
|
|
43
|
+
npm run start:stdio
|
|
44
|
+
|
|
45
|
+
# Streamable HTTP (distant, sans état) — gate OAuth 2.1 par défaut :
|
|
46
|
+
MCP_OAUTH_ISSUER=https://your-tenant.example.com \
|
|
47
|
+
MCP_OAUTH_AUDIENCE=https://your-mcp-server.example.com \
|
|
48
|
+
PORT=8787 npm run start:http
|
|
49
|
+
|
|
50
|
+
# Streamable HTTP, palier "Public MCP" sans authentification (local/self-host, appelant de confiance) :
|
|
51
|
+
AUTH_MODE=public PORT=8787 npm run start:http
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Paliers d'authentification
|
|
55
|
+
|
|
56
|
+
Deux paliers, selon `mcp-standard.md` "Authentication & Authorization" :
|
|
57
|
+
|
|
58
|
+
| `AUTH_MODE` | Comportement |
|
|
59
|
+
|---|---|
|
|
60
|
+
| `oauth` (par défaut) | Resource server OAuth 2.1 (`@vantageos/mcp-auth-kit`) : chaque appel HTTP `/mcp` exige un Bearer JWT RS256 valide, lié à l'audience/l'émetteur. Token manquant/invalide -> `401` + `WWW-Authenticate`. Les métadonnées RFC 9728 Protected Resource sont servies sur `/.well-known/oauth-protected-resource`. `/health` reste sans token. Nécessite `MCP_OAUTH_ISSUER` + `MCP_OAUTH_AUDIENCE`. |
|
|
61
|
+
| `public` | Aucun gate sur le transport HTTP — pour un usage local/self-host où l'appelant est déjà de confiance. Reprend le modèle de confiance du transport stdio (stdio n'a jamais eu de gate). Aucun document `.well-known/oauth-protected-resource` n'est servi dans ce mode (il n'y a pas de serveur d'autorisation à décrire). |
|
|
62
|
+
|
|
63
|
+
Le transport stdio (`stdio.ts`) n'est jamais gardé, dans aucun des deux modes
|
|
64
|
+
— le process local qui l'invoque EST l'appelant, selon le modèle de confiance
|
|
65
|
+
de `mcp-standard.md` pour les outils locaux/self-host.
|
|
66
|
+
|
|
67
|
+
`buildHttpApp()` appelé sans argument revient par défaut au palier `public` —
|
|
68
|
+
c'est ce que les tests du squelette de transport (`httpHandshake.test.ts`,
|
|
69
|
+
`protocolKitWiring.test.ts`) exercent, donc ils n'ont besoin d'aucune
|
|
70
|
+
configuration OAuth. Le point d'entrée de production (`http.ts`) résout
|
|
71
|
+
toujours `AUTH_MODE` depuis l'environnement via `config.ts`, avec `oauth`
|
|
72
|
+
comme valeur par défaut si non défini.
|
|
73
|
+
|
|
74
|
+
## i18n côté serveur (messages d'erreur FR/EN)
|
|
75
|
+
|
|
76
|
+
`src/i18n.ts` localise les messages d'erreur/validation MCP (rejet
|
|
77
|
+
d'authentification, refus de tenant, validation d'entrée d'outil) selon le
|
|
78
|
+
mandat bilingue de `mcp-standard.md` (§Bilingual) : le client envoie
|
|
79
|
+
`X-MCP-Locale: fr` ou `X-MCP-Locale: en` (par défaut `en` si absent), et
|
|
80
|
+
`src/httpApp.ts` + `src/mcpServerFactory.ts` acheminent le message
|
|
81
|
+
correspondant via `t(locale, key)`.
|
|
82
|
+
|
|
83
|
+
Les deux fichiers de ressources (`src/locales/{en,fr}.json`) suivent
|
|
84
|
+
exactement la convention de ressource à espace de noms livrée par
|
|
85
|
+
`@vantageos/mosaic-i18n@0.1.1`
|
|
86
|
+
(`node_modules/@vantageos/mosaic-i18n/src/locales/{en,fr}.json`) : un objet
|
|
87
|
+
plat `<Namespace>.<catégorie>.<clé>` -> chaîne, FR et EN maintenus clé pour
|
|
88
|
+
clé en parfait alignement. `mosaic-i18n` lui-même est un package
|
|
89
|
+
React/`react-i18next` et ne peut pas être appelé directement depuis un
|
|
90
|
+
serveur JSON-RPC, donc son API d'exécution n'est pas importée ici — la forme
|
|
91
|
+
de son fichier de ressources est réutilisée à la place, sous le namespace
|
|
92
|
+
`Mcp` propre à ce boilerplate.
|
|
93
|
+
|
|
94
|
+
## Tests
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
npm test
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Exécute les deux transports contre les vrais chemins de code du SDK officiel :
|
|
101
|
+
la suite HTTP pilote l'app Hono en mémoire ; la suite stdio lance le binaire
|
|
102
|
+
`dist/stdio.js` compilé comme un vrai process enfant via `StdioClientTransport`.
|
|
103
|
+
|
|
104
|
+
## Ajouter un outil
|
|
105
|
+
|
|
106
|
+
Enregistrez-le une seule fois dans `src/mcpServerFactory.ts` — il devient
|
|
107
|
+
alors disponible automatiquement sur les deux transports. Il n'y a aucune
|
|
108
|
+
route REST séparée à ajouter.
|
|
109
|
+
|
|
110
|
+
## Packaging & distribution
|
|
111
|
+
|
|
112
|
+
Ce boilerplate est lui-même un package npm publiable/clonable. Deux
|
|
113
|
+
artefacts portent son identité de distribution :
|
|
114
|
+
|
|
115
|
+
- `package.json` — le package npm. `files` ne livre que l'arbre `dist/`
|
|
116
|
+
compilé (serveur compilé + `dist/locales/` + `dist/ui-bundle/widget.html`),
|
|
117
|
+
le `README.md`, la `LICENSE`, le manifeste de plugin, et la config client
|
|
118
|
+
d'exemple — jamais `src/`, les tests, ou l'outillage. `main`/`types`/`exports`
|
|
119
|
+
pointent vers `dist/index.js` ; le bin `mcp-boilerplate` pointe vers
|
|
120
|
+
`dist/stdio.js`. `publishConfig.access = public` est requis pour le scope
|
|
121
|
+
`@vantageos`.
|
|
122
|
+
- `.claude-plugin/plugin.json` — le manifeste de catalogue Claude Code
|
|
123
|
+
marketplace / VantageRegistry, suivant la convention fleet des serveurs MCP
|
|
124
|
+
(miroir de `vantage-frameworks-mcp` / `vantage-agent-composer-mcp`) :
|
|
125
|
+
`name`, `version`, `description` bilingue + `description_fr`, `author`,
|
|
126
|
+
`license`, `homepage`, `category: "mcp-server"`, `bilingual: true`,
|
|
127
|
+
`keywords`.
|
|
128
|
+
|
|
129
|
+
### Scaffold → build → publish
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# 1. Scaffold : clonez ce repo (ou le tarball npm) comme squelette de votre serveur.
|
|
133
|
+
git clone https://github.com/elpiarthera/vantage-mcp-boilerplate.git my-mcp
|
|
134
|
+
cd my-mcp && npm install --legacy-peer-deps # voir la note de skew peer-range dev ci-dessous
|
|
135
|
+
|
|
136
|
+
# 2. Renommer : définissez "name"/"bin" dans package.json et "name" dans
|
|
137
|
+
# .claude-plugin/plugin.json pour votre serveur, puis ajoutez des outils dans src/mcpServerFactory.ts.
|
|
138
|
+
|
|
139
|
+
# 3. Build + vérification depuis un arbre propre (ce que CI et prepublishOnly imposent) :
|
|
140
|
+
rm -rf dist node_modules/.vite && npm run build && npm test && npm run evals
|
|
141
|
+
|
|
142
|
+
# 4. Inspectez le tarball avant publication — confirmez que dist/ est bien livré et que rien ne fuit :
|
|
143
|
+
npm pack --dry-run
|
|
144
|
+
|
|
145
|
+
# 5. Publiez sur les deux canaux :
|
|
146
|
+
npm publish # registre npm (prepublishOnly relance build+test+evals)
|
|
147
|
+
# Catalogue VantageRegistry : enregistrez .claude-plugin/plugin.json via
|
|
148
|
+
# le skill fleet create-plugin / generate-marketplace (upsert VR).
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
`prepublishOnly` relance `build → build:ui → test → evals` pour qu'un
|
|
152
|
+
tarball cassé ou contenant uniquement `src` ne puisse jamais atteindre npm.
|
|
153
|
+
Les canaux de distribution sont **npm** (le package exécutable) et le
|
|
154
|
+
**catalogue VantageRegistry / Claude Code marketplace** (découverte, via
|
|
155
|
+
`plugin.json`).
|
|
156
|
+
|
|
157
|
+
## Couche UI MCP Apps
|
|
158
|
+
|
|
159
|
+
`render_items_ui` affiche `EXAMPLE_ITEMS` comme un widget interactif via
|
|
160
|
+
l'officiel `@modelcontextprotocol/ext-apps/server` (`registerAppTool` +
|
|
161
|
+
`registerAppResource`), forme imbriquée GA `_meta.ui.resourceUri` (stable
|
|
162
|
+
depuis le 2026-01-26) — jamais la clé plate dépréciée `_meta["ui/resourceUri"]`.
|
|
163
|
+
Un repli markdown est toujours présent dans `content[0]`, même pour les
|
|
164
|
+
clients qui ne négocient jamais l'extension `io.modelcontextprotocol/ui`.
|
|
165
|
+
|
|
166
|
+
Le widget (`src/ui/`) réutilise une famille `MosaicCard` vendorisée
|
|
167
|
+
(`src/ui/mosaic-card.tsx` — atomes présentationnels, aucune dépendance
|
|
168
|
+
d'exécution) et est empaqueté en un seul fichier HTML autonome
|
|
169
|
+
(`vite-plugin-singlefile`, `dist/ui-bundle/widget.html`, ~70 Ko gzippé,
|
|
170
|
+
aucun fetch d'exécution externe). `npm run build:ui` produit ce bundle
|
|
171
|
+
indépendamment de `npm run build` (tsc), sur un chemin de sortie sans
|
|
172
|
+
collision (`dist/ui-bundle/` vs `dist/ui/` de tsc) — les deux étapes de
|
|
173
|
+
build écrivent sur des arbres `dist/ui*` d'apparence similaire mais jamais
|
|
174
|
+
sur le même répertoire, si bien que `emptyOutDir` côté vite ne peut jamais
|
|
175
|
+
supprimer un module serveur compilé par tsc.
|
|
176
|
+
|
|
177
|
+
**Hygiène du template** : les atomes `MosaicCard` sont vendorisés
|
|
178
|
+
localement plutôt qu'importés depuis `@vantageos/mosaic-blocks`, un paquet
|
|
179
|
+
interne sans version stable (non-alpha) publiée sur npm. Une
|
|
180
|
+
devDependency de template épinglée sur un tag alpha mouvant casse au
|
|
181
|
+
prochain bump alpha ; vendoriser les quatre primitives présentationnelles
|
|
182
|
+
réellement utilisées par le widget élimine ce mode de défaillance.
|
|
183
|
+
|
|
184
|
+
**Ordre de publication (exigence stricte)** : ce boilerplate dépend de
|
|
185
|
+
`@vantageos/mcp-protocol-kit@^0.2.0`. Le câblage de `tools/list` utilise
|
|
186
|
+
`buildToolsListResult` du kit, qui existe UNIQUEMENT à partir du kit 0.2.0+.
|
|
187
|
+
En semver 0.x, `^0.2.0` n'accepte PAS le 0.1.x, donc un `npm install` frais
|
|
188
|
+
depuis le registre résout la version du kit dont le code a réellement
|
|
189
|
+
besoin. Par conséquent, **le kit `@vantageos/mcp-protocol-kit` 0.2.0 DOIT
|
|
190
|
+
être publié sur npm AVANT que ce boilerplate puisse être installé ou publié
|
|
191
|
+
depuis le registre.** C'est un ordre strict, non optionnel : publiez d'abord
|
|
192
|
+
le kit, confirmez que 0.2.0 est en ligne sur le registre, puis publiez le
|
|
193
|
+
boilerplate.
|
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# @vantageos/mcp-boilerplate
|
|
2
2
|
|
|
3
|
+
SELLABLE AS: `mcp-boilerplate` — a clonable MCP server starter for the Claude Code marketplace / VantageRegistry catalogue, published as `@vantageos/mcp-boilerplate` on npm.
|
|
4
|
+
|
|
3
5
|
A clonable MCP server skeleton: dual-transport bootstrap (stdio + Streamable
|
|
4
6
|
HTTP, stateless) built exclusively on the official
|
|
5
7
|
[`@modelcontextprotocol/sdk`](https://www.npmjs.com/package/@modelcontextprotocol/sdk)
|
|
@@ -155,8 +157,9 @@ official `@modelcontextprotocol/ext-apps/server` (`registerAppTool` +
|
|
|
155
157
|
markdown fallback is always present in `content[0]`, even for clients that
|
|
156
158
|
never negotiate the `io.modelcontextprotocol/ui` extension.
|
|
157
159
|
|
|
158
|
-
The widget (`src/ui/`) reuses
|
|
159
|
-
|
|
160
|
+
The widget (`src/ui/`) reuses a vendored `MosaicCard` family
|
|
161
|
+
(`src/ui/mosaic-card.tsx` — style-only presentational atoms, no runtime
|
|
162
|
+
dependency) and is bundled to a single self-contained HTML file
|
|
160
163
|
(`vite-plugin-singlefile`, `dist/ui-bundle/widget.html`, ~70 KB gzipped, no
|
|
161
164
|
external runtime fetch). `npm run build:ui` produces this bundle
|
|
162
165
|
independently of `npm run build` (tsc), on a non-colliding output path
|
|
@@ -165,13 +168,12 @@ same-looking `dist/ui*` tree but never share a directory, so
|
|
|
165
168
|
`emptyOutDir` on the vite side can never delete a tsc-compiled server
|
|
166
169
|
module.
|
|
167
170
|
|
|
168
|
-
**
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
build under the `^0.3.0` runtime dependency, proving no runtime conflict.
|
|
171
|
+
**Template hygiene**: the `MosaicCard` atoms are vendored locally rather
|
|
172
|
+
than pulled from `@vantageos/mosaic-blocks`, an internal package with no
|
|
173
|
+
stable (non-alpha) npm release. A fork-template devDependency pinned to a
|
|
174
|
+
moving alpha tag breaks on the next alpha bump; vendoring the four
|
|
175
|
+
presentational primitives the widget actually uses removes that failure
|
|
176
|
+
mode entirely.
|
|
175
177
|
|
|
176
178
|
**Publish ordering (hard requirement)**: this boilerplate depends on
|
|
177
179
|
`@vantageos/mcp-protocol-kit@^0.2.0`. The `tools/list` wiring uses the kit's
|
package/dist/mcpServerFactory.js
CHANGED
|
@@ -158,8 +158,27 @@ export function createBoilerplateMcpServer(deps = {}) {
|
|
|
158
158
|
// top of the standard `tools` array every MCP client expects. The kit's
|
|
159
159
|
// `buildToolsListResult` (0.2.0+) emits the `tools` key the official
|
|
160
160
|
// `ListToolsResultSchema` requires directly — no hand alias needed.
|
|
161
|
-
|
|
162
|
-
|
|
161
|
+
//
|
|
162
|
+
// DERIVATION (not a hand-typed descriptor list): the SDK's own McpServer
|
|
163
|
+
// already builds the `tools/list` response from its single source of
|
|
164
|
+
// truth — `this._registeredTools`, populated by every `registerTool`/
|
|
165
|
+
// `registerAppTool` call above — and installs that handler on
|
|
166
|
+
// `server.server` (the low-level `Server`) via `setToolRequestHandlers()`
|
|
167
|
+
// BEFORE this function runs. Re-invoking that already-installed handler,
|
|
168
|
+
// then re-shaping its `tools` array through the kit, means a 4th
|
|
169
|
+
// registered tool appears here automatically — nothing here enumerates
|
|
170
|
+
// tool names by hand, so a tool can never again be silently missing from
|
|
171
|
+
// discovery just because this list forgot to mention it.
|
|
172
|
+
const baseListToolsHandler = server.server._requestHandlers.get("tools/list");
|
|
173
|
+
if (!baseListToolsHandler) {
|
|
174
|
+
throw new Error("tools/list handler not found on the SDK's Server — McpServer.registerTool() " +
|
|
175
|
+
"installs it lazily on first registration; this indicates no tool was ever " +
|
|
176
|
+
"registered, which is a boilerplate wiring bug, not a runtime condition to " +
|
|
177
|
+
"silently work around.");
|
|
178
|
+
}
|
|
179
|
+
server.server.setRequestHandler(ListToolsRequestSchema, async (request, extra) => {
|
|
180
|
+
const { tools } = await baseListToolsHandler(request, extra);
|
|
181
|
+
return buildToolsListResult(tools, {
|
|
163
182
|
ttlMs: 60_000,
|
|
164
183
|
cacheScope: "public",
|
|
165
184
|
});
|
package/dist/stdio.js
CHANGED
|
@@ -8,7 +8,14 @@
|
|
|
8
8
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
9
9
|
import { createBoilerplateMcpServer } from "./mcpServerFactory.js";
|
|
10
10
|
export async function startStdioServer() {
|
|
11
|
-
|
|
11
|
+
// `requireTenant` is otherwise only reachable from the OAuth-tier HTTP
|
|
12
|
+
// transport (see httpApp.ts). This env toggle exists solely so the eval
|
|
13
|
+
// suite (evals/evals.json "list-items-requires-tenant-refusal") can
|
|
14
|
+
// exercise the ALREADY-EXISTING `list_items` tenant-refusal branch in
|
|
15
|
+
// mcpServerFactory.ts through the real stdio transport, without adding a
|
|
16
|
+
// new code path. Unset by default — normal stdio usage is unaffected.
|
|
17
|
+
const requireTenant = process.env.MCP_BOILERPLATE_REQUIRE_TENANT === "1";
|
|
18
|
+
const server = createBoilerplateMcpServer({ requireTenant });
|
|
12
19
|
const transport = new StdioServerTransport();
|
|
13
20
|
await server.connect(transport);
|
|
14
21
|
process.stderr.write("[mcp-boilerplate] stdio server started — 1 tool available\n");
|