mcp-expose 1.1.1 → 1.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/CHANGELOG.md +16 -1
- package/README.md +58 -9
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,20 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [1.1.2] - 2026-09-28
|
|
10
|
+
|
|
11
|
+
### Documentation
|
|
12
|
+
|
|
13
|
+
- README: every framework guide example (NestJS, Express, Fastify, Koa, Hono, AdonisJS, OpenAPI gateway) now shows
|
|
14
|
+
`transformResponse`; the version compatibility section says what each framework version is verified for (including
|
|
15
|
+
OAuth and `transformResponse`), the `transformResponse` section names the marker for every framework, and
|
|
16
|
+
`ctx.callRoute()` documents each framework's path prefixes.
|
|
17
|
+
|
|
18
|
+
### Tests
|
|
19
|
+
|
|
20
|
+
- `transformResponse` with `ctx.callRoute()` is checked end to end on every supported framework version (NestJS 10-12,
|
|
21
|
+
Express 3-5, Fastify 3-5, Koa 1-3, Hono 2-4, AdonisJS 6-7, OpenAPI gateway), with and without OAuth.
|
|
22
|
+
|
|
9
23
|
## [1.1.1] - 2026-09-28
|
|
10
24
|
|
|
11
25
|
### Added
|
|
@@ -68,7 +82,8 @@ options, default tool naming) now follows Semantic Versioning.
|
|
|
68
82
|
- Path parameters that are empty, `.` or `..` are rejected, so an agent cannot use them to reach routes
|
|
69
83
|
that were never exposed as tools (for example `/orders/../admin`).
|
|
70
84
|
|
|
71
|
-
[Unreleased]: https://github.com/NITINKACHHADIYA/Node-MCP/compare/v1.1.
|
|
85
|
+
[Unreleased]: https://github.com/NITINKACHHADIYA/Node-MCP/compare/v1.1.2...HEAD
|
|
86
|
+
[1.1.2]: https://github.com/NITINKACHHADIYA/Node-MCP/releases/tag/v1.1.2
|
|
72
87
|
[1.1.1]: https://github.com/NITINKACHHADIYA/Node-MCP/releases/tag/v1.1.1
|
|
73
88
|
[1.1.0]: https://github.com/NITINKACHHADIYA/Node-MCP/releases/tag/v1.1.0
|
|
74
89
|
[1.0.0]: https://github.com/NITINKACHHADIYA/Node-MCP/releases/tag/v1.0.0
|
package/README.md
CHANGED
|
@@ -125,7 +125,9 @@ Tools are discovered **lazily on the first MCP request**, so the order you regis
|
|
|
125
125
|
|
|
126
126
|
mcp-expose supports the **current major version of each framework and the two before it**. Every row
|
|
127
127
|
below runs in CI as a real project (see [`e2e/`](e2e/README.md)): the packed library is installed from its
|
|
128
|
-
tarball and the app is driven by the official MCP SDK client, on Node.js 20, 22 and 24.
|
|
128
|
+
tarball and the app is driven by the official MCP SDK client, on Node.js 20, 22 and 24. Each row is checked for tool
|
|
129
|
+
discovery, auth forwarding, the app's own validation errors, [OAuth](#oauth-sign-in-from-ai-clients) and
|
|
130
|
+
[`transformResponse`](#shaping-and-enriching-responses), with and without the `oauth` option.
|
|
129
131
|
|
|
130
132
|
| Framework | Supported majors | Notes |
|
|
131
133
|
| --------- | ---------------- | ------------------------------------------------------------------------------------ |
|
|
@@ -197,7 +199,16 @@ export class CreateOrderDto {
|
|
|
197
199
|
@UseGuards(JwtAuthGuard) // ← still enforced for every tool call
|
|
198
200
|
export class OrdersController {
|
|
199
201
|
@Get(':id')
|
|
200
|
-
@McpTool({
|
|
202
|
+
@McpTool({
|
|
203
|
+
description: 'Get one order by its id.',
|
|
204
|
+
// Optional: shape what the agent sees. Hide internal fields, add the customer from another route.
|
|
205
|
+
transformResponse: async (res, ctx) => {
|
|
206
|
+
if (!res.ok) return undefined; // keep the default error result
|
|
207
|
+
const { internalNotes, ...order } = res.json as Order;
|
|
208
|
+
const customer = await ctx.callRoute({ path: '/api/customers/:id', params: { id: order.customerId } });
|
|
209
|
+
return { ...order, customer: customer.json };
|
|
210
|
+
},
|
|
211
|
+
})
|
|
201
212
|
findOne(@Param('id', ParseIntPipe) id: number) { … }
|
|
202
213
|
|
|
203
214
|
@Post()
|
|
@@ -271,6 +282,9 @@ app.get(
|
|
|
271
282
|
name: 'search_products',
|
|
272
283
|
description: 'Search the product catalog by name.',
|
|
273
284
|
query: { type: 'object', properties: { q: { type: 'string' } } },
|
|
285
|
+
// Optional: only send the fields the agent needs
|
|
286
|
+
transformResponse: (res) =>
|
|
287
|
+
res.ok ? (res.json as { items: Product[] }).items.map(({ id, name, price }) => ({ id, name, price })) : undefined,
|
|
274
288
|
}),
|
|
275
289
|
searchProducts,
|
|
276
290
|
);
|
|
@@ -335,7 +349,14 @@ app.post(
|
|
|
335
349
|
required: ['title'],
|
|
336
350
|
},
|
|
337
351
|
},
|
|
338
|
-
config: {
|
|
352
|
+
config: {
|
|
353
|
+
mcp: {
|
|
354
|
+
name: 'add_todo',
|
|
355
|
+
description: 'Add a todo item.',
|
|
356
|
+
// Optional: shape the response the agent sees
|
|
357
|
+
transformResponse: (res) => (res.ok ? { created: true, id: (res.json as Todo).id } : undefined),
|
|
358
|
+
},
|
|
359
|
+
}, // or `mcp: true`
|
|
339
360
|
},
|
|
340
361
|
addTodo,
|
|
341
362
|
);
|
|
@@ -357,7 +378,15 @@ const app = new Koa();
|
|
|
357
378
|
const router = new Router({ prefix: '/api' });
|
|
358
379
|
|
|
359
380
|
// Step 1: mark routes
|
|
360
|
-
router.get(
|
|
381
|
+
router.get(
|
|
382
|
+
'/weather/:city',
|
|
383
|
+
mcpTool({
|
|
384
|
+
description: 'Current weather for a city.',
|
|
385
|
+
// Optional: add a hint for the agent
|
|
386
|
+
transformResponse: (res) => (res.ok ? { ...(res.json as object), unit: 'celsius' } : undefined),
|
|
387
|
+
}),
|
|
388
|
+
getWeather,
|
|
389
|
+
);
|
|
361
390
|
|
|
362
391
|
// Step 2: mount the endpoint (before your routers) and list the routers to scan
|
|
363
392
|
mountMcp(app, { name: 'weather-api', routers: [router] });
|
|
@@ -392,7 +421,13 @@ const app = new Hono();
|
|
|
392
421
|
|
|
393
422
|
app.post(
|
|
394
423
|
'/notes',
|
|
395
|
-
mcpTool({
|
|
424
|
+
mcpTool({
|
|
425
|
+
name: 'create_note',
|
|
426
|
+
description: 'Save a note.',
|
|
427
|
+
body: z.object({ text: z.string() }),
|
|
428
|
+
// Optional: shape the response the agent sees
|
|
429
|
+
transformResponse: (res) => (res.ok ? { saved: true, id: (res.json as Note).id } : undefined),
|
|
430
|
+
}),
|
|
396
431
|
bearerAuth({ token }),
|
|
397
432
|
async (c) => c.json(await saveNote(await c.req.json()), 201),
|
|
398
433
|
);
|
|
@@ -419,7 +454,16 @@ const OrdersController = () => import('#controllers/orders_controller');
|
|
|
419
454
|
router
|
|
420
455
|
.group(() => {
|
|
421
456
|
// Step 1: mark routes. Group prefixes and middleware (auth, throttle) all apply.
|
|
422
|
-
router.get('orders/:id', [OrdersController, 'show']).mcp({
|
|
457
|
+
router.get('orders/:id', [OrdersController, 'show']).mcp({
|
|
458
|
+
description: 'Get an order by id',
|
|
459
|
+
// Optional: add the customer from another route (same auth). Paths include the group prefix.
|
|
460
|
+
transformResponse: async (res, ctx) => {
|
|
461
|
+
if (!res.ok) return undefined;
|
|
462
|
+
const order = res.json as Order;
|
|
463
|
+
const customer = await ctx.callRoute({ path: '/api/v1/customers/:id', params: { id: order.customerId } });
|
|
464
|
+
return { ...order, customer: customer.json };
|
|
465
|
+
},
|
|
466
|
+
});
|
|
423
467
|
|
|
424
468
|
// A VineJS 4 validator (AdonisJS 7) can be passed as the schema directly
|
|
425
469
|
router
|
|
@@ -455,6 +499,8 @@ import { mountMcp } from 'mcp-expose/express';
|
|
|
455
499
|
const spec = await fetch('https://api.example.com/openapi.json').then((r) => r.json());
|
|
456
500
|
const tools = toolsFromOpenApi(spec, createFetchDispatcher({ baseUrl: 'https://api.example.com' }), {
|
|
457
501
|
include: ({ method }) => method === 'get', // e.g. only read-only operations
|
|
502
|
+
// Optional: shape responses of the generated tools (ctx.tool is the tool name)
|
|
503
|
+
transformResponse: (res, ctx) => (ctx.tool === 'get_user' && res.ok ? redact(res.json) : undefined),
|
|
458
504
|
});
|
|
459
505
|
|
|
460
506
|
const app = express();
|
|
@@ -670,8 +716,9 @@ routes. The route stays a route tool; there is no need to rewrite it as a custom
|
|
|
670
716
|
findOne(@Param('id') id: string) { ... }
|
|
671
717
|
```
|
|
672
718
|
|
|
673
|
-
It works the same with every marker
|
|
674
|
-
|
|
719
|
+
It works the same with every marker and every supported framework version: `@McpTool({ transformResponse })` (NestJS),
|
|
720
|
+
`mcpTool({ transformResponse })` (Express, Koa, Hono; `mcpToolLegacy()` on Koa 1), `config: { mcp: { transformResponse } }`
|
|
721
|
+
(Fastify), `.mcp({ transformResponse })` (AdonisJS) and `toolsFromOpenApi(doc, dispatch, { transformResponse })`.
|
|
675
722
|
|
|
676
723
|
**What the hook receives**
|
|
677
724
|
|
|
@@ -681,7 +728,9 @@ It works the same with every marker: `mcpTool({ transformResponse })`, `config:
|
|
|
681
728
|
- `ctx.defaultResult()`: the result mcp-expose would return without the hook.
|
|
682
729
|
- `ctx.callRoute({ method, path, params, query, body, headers })`: calls another route of the same app.
|
|
683
730
|
- It forwards the same credentials (`Authorization`, cookies) and runs through the same middleware, guards and validation.
|
|
684
|
-
- `path` is the full path as your server sees it, including
|
|
731
|
+
- `path` is the full path as your server sees it, including every prefix: NestJS global prefix and URI version
|
|
732
|
+
(`/api/v1/...`), Express router mount path, Koa router `prefix`, Hono `app.route()` mount, AdonisJS group `.prefix()`.
|
|
733
|
+
`ctx.request.path` shows the full path of the tool's own route. Fill `:id` / `{id}`
|
|
685
734
|
placeholders from `params`: values are URL-encoded, and `.` or `..` are rejected, so agent input can't redirect the call.
|
|
686
735
|
|
|
687
736
|
**What it returns**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-expose",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "Turn the HTTP routes of your existing Node.js app (NestJS, Express, Fastify, Koa, Hono, AdonisJS) into MCP tools for AI agents, reusing your auth, validation and rate limits.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mcp",
|