@tigerdata/mcp-boilerplate 1.1.0 → 1.2.0

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.
@@ -16,7 +16,7 @@ export async function cliEntrypoint(stdioEntrypoint, httpEntrypoint, instrumenta
16
16
  case 'http': {
17
17
  let cleanup;
18
18
  if (args.includes('--instrument') ||
19
- process.env.INSTRUMENT === 'true') {
19
+ process.env.INSTRUMENT?.toLowerCase().trim() === 'true') {
20
20
  const { instrument } = await import(instrumentation);
21
21
  ({ cleanup } = instrument());
22
22
  }
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import type { Server } from 'node:http';
3
- import express from 'express';
3
+ import express, { type Router } from 'express';
4
4
  import { type AdditionalSetupArgs } from './mcpServer.js';
5
5
  import type { BaseApiFactory, BasePromptFactory, ResourceFactory } from './types.js';
6
- export declare const httpServerFactory: <Context extends Record<string, unknown>>({ name, version, context, apiFactories, promptFactories, resourceFactories, additionalSetup, cleanupFn, stateful, instructions, }: {
6
+ interface HttpServerOptions<Context extends Record<string, unknown>> {
7
7
  name: string;
8
8
  version?: string;
9
9
  context: Context;
@@ -14,10 +14,28 @@ export declare const httpServerFactory: <Context extends Record<string, unknown>
14
14
  cleanupFn?: () => void | Promise<void>;
15
15
  stateful?: boolean;
16
16
  instructions?: string;
17
- }) => Promise<{
18
- app: express.Express;
19
- server: Server;
17
+ /**
18
+ * When provided, mount routers on this app/router instead of creating a new
19
+ * one. The caller owns the server lifecycle — `httpServerFactory` will not
20
+ * call `app.listen()`. The returned `server` will be `null`.
21
+ */
22
+ app?: Router;
23
+ /**
24
+ * Path to mount the MCP router at. Defaults to `"/mcp"`.
25
+ */
26
+ mcpPath?: string;
27
+ /**
28
+ * Path to mount the API router at. Defaults to `"/api"`.
29
+ */
30
+ apiPath?: string;
31
+ }
32
+ interface HttpServerResult {
33
+ app: Router;
34
+ /** `null` when an external `app` was provided (caller owns the server). */
35
+ server: Server | null;
20
36
  apiRouter: express.Router;
21
37
  mcpRouter: express.Router;
22
38
  registerCleanupFn: (fn: () => Promise<void>) => void;
23
- }>;
39
+ }
40
+ export declare const httpServerFactory: <Context extends Record<string, unknown>>({ name, version, context, apiFactories, promptFactories, resourceFactories, additionalSetup, cleanupFn, stateful, instructions, app: externalApp, mcpPath, apiPath, }: HttpServerOptions<Context>) => Promise<HttpServerResult>;
41
+ export {};
@@ -7,14 +7,21 @@ import { log } from './logger.js';
7
7
  import { mcpServerFactory } from './mcpServer.js';
8
8
  import { registerExitHandlers } from './registerExitHandlers.js';
9
9
  import { StatusError } from './StatusError.js';
10
- export const httpServerFactory = async ({ name, version, context, apiFactories = [], promptFactories, resourceFactories, additionalSetup, cleanupFn, stateful = true, instructions, }) => {
10
+ export const httpServerFactory = async ({ name, version, context, apiFactories = [], promptFactories, resourceFactories, additionalSetup, cleanupFn, stateful = true, instructions, app: externalApp, mcpPath = '/mcp', apiPath = '/api', }) => {
11
11
  const cleanupFns = cleanupFn
12
12
  ? [cleanupFn]
13
13
  : [];
14
14
  const exitHandler = registerExitHandlers(cleanupFns);
15
- log.info('Starting HTTP server...');
16
- const app = express();
17
- app.enable('trust proxy');
15
+ let app;
16
+ let ownApp;
17
+ if (externalApp) {
18
+ app = externalApp;
19
+ }
20
+ else {
21
+ ownApp = express();
22
+ ownApp.enable('trust proxy');
23
+ app = ownApp;
24
+ }
18
25
  const PORT = process.env.PORT || 3001;
19
26
  const inspector = process.env.NODE_ENV !== 'production' ||
20
27
  ['1', 'true'].includes(process.env.ENABLE_INSPECTOR ?? '0');
@@ -30,10 +37,10 @@ export const httpServerFactory = async ({ name, version, context, apiFactories =
30
37
  instructions,
31
38
  }), { name, stateful, inspector });
32
39
  cleanupFns.push(mcpCleanup);
33
- app.use('/mcp', mcpRouter);
40
+ app.use(mcpPath, mcpRouter);
34
41
  const [apiRouter, apiCleanup] = await apiRouterFactory(context, apiFactories);
35
42
  cleanupFns.push(apiCleanup);
36
- app.use('/api', apiRouter);
43
+ app.use(apiPath, apiRouter);
37
44
  // Error handler
38
45
  app.use((err, _req, res, _next) => {
39
46
  if (err instanceof StatusError && err.status < 500) {
@@ -49,19 +56,34 @@ export const httpServerFactory = async ({ name, version, context, apiFactories =
49
56
  .status(err instanceof StatusError ? err.status : 500)
50
57
  .json({ error: err.message });
51
58
  });
52
- if (inspector) {
59
+ if (inspector && 'listen' in app) {
60
+ const expressApp = app;
53
61
  process.env.MCP_USE_ANONYMIZED_TELEMETRY = 'false';
54
62
  import('@mcp-use/inspector')
55
63
  .then(({ mountInspector }) => {
56
- app.use(bodyParser.json());
57
- mountInspector(app, {
64
+ expressApp.use(bodyParser.json());
65
+ mountInspector(expressApp, {
58
66
  autoConnectUrl: process.env.MCP_PUBLIC_URL ?? `http://localhost:${PORT}/mcp`,
59
67
  });
60
68
  })
61
69
  .catch(log.error);
62
70
  }
63
- // Start the server
64
- const server = app.listen(PORT, async (error) => {
71
+ // When an external app is provided, the caller owns the server lifecycle.
72
+ if (externalApp) {
73
+ return {
74
+ app,
75
+ server: null,
76
+ apiRouter,
77
+ mcpRouter,
78
+ registerCleanupFn: (fn) => {
79
+ cleanupFns.push(fn);
80
+ },
81
+ };
82
+ }
83
+ // Start the server (ownApp is guaranteed to exist here — we returned early for external apps)
84
+ if (!ownApp)
85
+ throw new Error('Expected own Express app');
86
+ const server = ownApp.listen(PORT, async (error) => {
65
87
  if (error) {
66
88
  log.error('Error starting HTTP server:', error);
67
89
  exitHandler(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tigerdata/mcp-boilerplate",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "MCP boilerplate code for Node.js",
5
5
  "license": "Apache-2.0",
6
6
  "author": "TigerData",