@mcp-rune/create 0.11.0 → 0.11.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/README.md +6 -0
- package/dist/commands/add-model.js +1 -1
- package/dist/render/copy-tree.js +1 -1
- package/package.json +1 -1
- package/templates/advanced/.env.example.ejs +11 -0
- package/templates/advanced/__only_if_hasHttp__/src/servers/remote.ts.ejs +1 -1
- package/templates/advanced/__only_if_usePinoLogger__/src/observability/logger.ts +12 -0
- package/templates/advanced/config/schema.ts.ejs +7 -2
- package/templates/advanced/src/config.ts.ejs +43 -5
- package/templates/simple/.env.example +5 -0
package/README.md
CHANGED
|
@@ -147,6 +147,12 @@ These change the run itself — they don't answer a question, so they only appea
|
|
|
147
147
|
| `--offline-template <path>` | Use a local template directory instead of fetching via `tiged`. |
|
|
148
148
|
| `--mcp-rune-local <path>` | Point the scaffolded project at a local `mcp-rune` checkout (also reads `MCP_RUNE_LOCAL_PATH`). |
|
|
149
149
|
|
|
150
|
+
## Logging in generated projects
|
|
151
|
+
|
|
152
|
+
Generated projects log via the framework logger (or Pino with `--logger pino`). Log behavior is controlled by env vars — `LOG_LEVEL` (`error|warn|info|debug`), `LOG_FORMAT` (`text|json`), `LOG_FILE_FORMAT`, `LOG_FILE_ENABLED`, and `NODE_ENV` (production forces JSON). `LOG_LEVEL=debug rune-app` works out of the box, since the logger honors these at startup.
|
|
153
|
+
|
|
154
|
+
The **advanced** preset goes further: its `config/schema.js` spreads mcp-rune's `frameworkConfigSchema`, so those vars are validated by `loadConfig` and applied to the logger via `configureLogging()` in `src/config.ts` — one source of truth, no stray `process.env` reads. The **simple** preset relies on the logger's bootstrap defaults. See each preset's `.env.example`.
|
|
155
|
+
|
|
150
156
|
## Templates
|
|
151
157
|
|
|
152
158
|
As an alternative to presets, scaffold from a runnable example in the [`mcp-rune/examples`](https://github.com/mcp-rune/examples) repo:
|
|
@@ -118,7 +118,7 @@ function makeVars(cwd, preset, models) {
|
|
|
118
118
|
useLangfuse: false,
|
|
119
119
|
toolClasses: [],
|
|
120
120
|
promptStrategies: {},
|
|
121
|
-
mcpRuneVersion: pkg.dependencies?.['@mcp-rune/mcp-rune'] ?? '^0.
|
|
121
|
+
mcpRuneVersion: pkg.dependencies?.['@mcp-rune/mcp-rune'] ?? '^0.105.1',
|
|
122
122
|
nodeEngine: '>=24.0.0',
|
|
123
123
|
};
|
|
124
124
|
}
|
package/dist/render/copy-tree.js
CHANGED
|
@@ -128,7 +128,7 @@ function makeVars(answers) {
|
|
|
128
128
|
toolClasses: answers.toolClasses ?? [],
|
|
129
129
|
promptStrategies: answers.promptStrategies ?? {},
|
|
130
130
|
models: normalizeModels(answers.models),
|
|
131
|
-
mcpRuneVersion: answers.mcpRuneVersion ?? '^0.
|
|
131
|
+
mcpRuneVersion: answers.mcpRuneVersion ?? '^0.105.1',
|
|
132
132
|
nodeEngine: answers.nodeEngine ?? '>=24.0.0',
|
|
133
133
|
};
|
|
134
134
|
}
|
package/package.json
CHANGED
|
@@ -80,3 +80,14 @@ LANGFUSE_SECRET_KEY=
|
|
|
80
80
|
# LANGFUSE_PUBLIC_KEY=
|
|
81
81
|
# LANGFUSE_SECRET_KEY=
|
|
82
82
|
<% } -%>
|
|
83
|
+
|
|
84
|
+
# =============================================================================
|
|
85
|
+
# Logging (optional)
|
|
86
|
+
# =============================================================================
|
|
87
|
+
# Declared via frameworkConfigSchema (spread into config/schema.js) and applied
|
|
88
|
+
# by configureLogging() in src/config.ts, so these are validated config — not
|
|
89
|
+
# loose env reads. LOG_LEVEL=debug also works ad-hoc when debugging.
|
|
90
|
+
# LOG_LEVEL=info # error | warn | info | debug
|
|
91
|
+
# LOG_FORMAT=json # text (default) | json; NODE_ENV=production forces json
|
|
92
|
+
# LOG_FILE_FORMAT=json # file format; inherits LOG_FORMAT if unset
|
|
93
|
+
# LOG_FILE_ENABLED=false # write rotating daily files under logs/
|
|
@@ -17,7 +17,7 @@ const { config, createOAuthService, mcpConfig } = await import('../config.js')
|
|
|
17
17
|
|
|
18
18
|
const port = config.transport.remote.port
|
|
19
19
|
const baseUrl = config.transport.remote.baseUrl ?? `http://localhost:${port}`
|
|
20
|
-
const isProduction = config.
|
|
20
|
+
const isProduction = config.runtime.environment === 'production'
|
|
21
21
|
|
|
22
22
|
const server = new HttpServer({
|
|
23
23
|
port,
|
|
@@ -19,6 +19,10 @@ interface ChildLogger {
|
|
|
19
19
|
child: (meta: Record<string, unknown>) => ChildLogger
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
// Bootstrap level honors LOG_LEVEL (the usual pino/12-factor convention) so
|
|
23
|
+
// logging works before config is loaded. `configureLogging()` below lets the
|
|
24
|
+
// validated config supersede it — keeping a single source of truth once
|
|
25
|
+
// loadConfig has run.
|
|
22
26
|
const base = pino({
|
|
23
27
|
level: process.env.LOG_LEVEL ?? 'info',
|
|
24
28
|
formatters: {
|
|
@@ -56,6 +60,14 @@ export const logger = {
|
|
|
56
60
|
setApp(name: string): void {
|
|
57
61
|
appName = name
|
|
58
62
|
},
|
|
63
|
+
/**
|
|
64
|
+
* Apply validated logging config (from loadConfig), superseding the
|
|
65
|
+
* LOG_LEVEL bootstrap. Mirrors the framework logger's configureLogging so
|
|
66
|
+
* config.ts can wire both with one shape.
|
|
67
|
+
*/
|
|
68
|
+
configureLogging(opts: { level?: string } = {}): void {
|
|
69
|
+
if (opts.level) base.level = opts.level
|
|
70
|
+
},
|
|
59
71
|
child(meta: Record<string, unknown> = {}): ChildLogger {
|
|
60
72
|
return buildChild(meta)
|
|
61
73
|
}
|
|
@@ -5,9 +5,14 @@
|
|
|
5
5
|
* at startup. Every env var read in the codebase should be declared here.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type
|
|
8
|
+
import { frameworkConfigSchema, type ConfigSchema } from '@mcp-rune/mcp-rune/core'
|
|
9
9
|
|
|
10
10
|
export const configSchema = {
|
|
11
|
+
// Framework-owned logging + runtime vars (logging.* → LOG_*,
|
|
12
|
+
// runtime.environment → NODE_ENV). Applied to the logger in config.ts via
|
|
13
|
+
// configureLogging() so the validated values supersede the env bootstrap.
|
|
14
|
+
...frameworkConfigSchema,
|
|
15
|
+
|
|
11
16
|
api: {
|
|
12
17
|
url: {
|
|
13
18
|
env: 'API_URL',
|
|
@@ -104,7 +109,7 @@ export const configSchema = {
|
|
|
104
109
|
|
|
105
110
|
http: {
|
|
106
111
|
corsOrigins: { env: 'CORS_ORIGINS', doc: 'Comma-separated list of allowed CORS origins' },
|
|
107
|
-
|
|
112
|
+
// NODE_ENV is provided by frameworkConfigSchema as runtime.environment.
|
|
108
113
|
},
|
|
109
114
|
|
|
110
115
|
errorTracking: {
|
|
@@ -12,11 +12,14 @@ import { createServer as createServerFactory } from '@mcp-rune/mcp-rune/server'
|
|
|
12
12
|
import { _setAdapter, OAuthService, PostgresqlAdapter } from '@mcp-rune/mcp-rune/oauth2'
|
|
13
13
|
<% } -%>
|
|
14
14
|
<% if (usePinoLogger) { -%>
|
|
15
|
-
|
|
15
|
+
// Your app logs via Pino (below), but mcp-rune's internals log via the
|
|
16
|
+
// framework logger — configure it from the same validated config.
|
|
17
|
+
import { errorTracking, logger as frameworkLogger, tracing, vectorStorage } from '@mcp-rune/mcp-rune/runtime'
|
|
16
18
|
<% } else { -%>
|
|
17
19
|
import { errorTracking, logger, tracing, vectorStorage } from '@mcp-rune/mcp-rune/runtime'
|
|
18
20
|
<% } -%>
|
|
19
21
|
import { createPgvectorAdapter } from '@mcp-rune/mcp-rune/runtime/vendor/pgvector'
|
|
22
|
+
import { assertMigrationsCurrent, type Feature } from '@mcp-rune/mcp-rune/db/migrations'
|
|
20
23
|
|
|
21
24
|
import { configSchema } from '../config/schema.js'
|
|
22
25
|
import { closeDatabase, initDatabase } from './db.js'
|
|
@@ -67,7 +70,15 @@ interface AppConfig {
|
|
|
67
70
|
}
|
|
68
71
|
<% } -%>
|
|
69
72
|
}
|
|
70
|
-
http: { corsOrigins: string | undefined
|
|
73
|
+
http: { corsOrigins: string | undefined }
|
|
74
|
+
// From frameworkConfigSchema (spread into configSchema):
|
|
75
|
+
logging: {
|
|
76
|
+
level: string
|
|
77
|
+
format?: 'text' | 'json'
|
|
78
|
+
fileFormat?: 'text' | 'json'
|
|
79
|
+
fileEnabled: boolean
|
|
80
|
+
}
|
|
81
|
+
runtime: { environment: string }
|
|
71
82
|
errorTracking: { sentryDsn: string | undefined }
|
|
72
83
|
tracing: { langfusePublicKey: string | undefined; langfuseSecretKey: string | undefined }
|
|
73
84
|
}
|
|
@@ -88,10 +99,28 @@ const { name: SERVER_NAME, version: SERVER_VERSION } = startup.phase(
|
|
|
88
99
|
export const config = startup.phase('config', 'Load configuration', (log) => {
|
|
89
100
|
const cfg = loadConfig(configSchema)
|
|
90
101
|
log.debug(cfg.toString())
|
|
91
|
-
|
|
102
|
+
const appCfg = cfg as unknown as AppConfig & { toString(): string }
|
|
103
|
+
// Apply the validated logging config, superseding the framework logger's
|
|
104
|
+
// env-derived bootstrap. No process.env reads — the loaded config is the
|
|
105
|
+
// single source of truth.
|
|
106
|
+
<% if (usePinoLogger) { -%>
|
|
107
|
+
// Framework internals log via the framework logger; your app logs via Pino.
|
|
108
|
+
// Configure both from the same validated config.
|
|
109
|
+
frameworkLogger.configureLogging({
|
|
110
|
+
...appCfg.logging,
|
|
111
|
+
production: appCfg.runtime.environment === 'production',
|
|
112
|
+
})
|
|
113
|
+
logger.configureLogging({ level: appCfg.logging.level })
|
|
114
|
+
<% } else { -%>
|
|
115
|
+
logger.configureLogging({
|
|
116
|
+
...appCfg.logging,
|
|
117
|
+
production: appCfg.runtime.environment === 'production',
|
|
118
|
+
})
|
|
119
|
+
<% } -%>
|
|
120
|
+
return appCfg
|
|
92
121
|
})
|
|
93
122
|
|
|
94
|
-
const isProduction = config.
|
|
123
|
+
const isProduction = config.runtime.environment === 'production'
|
|
95
124
|
|
|
96
125
|
startup.phase('error-tracking', 'Error tracking', () => {
|
|
97
126
|
// Vendor (Sentry) reads SENTRY_DSN + NODE_ENV from env directly; the
|
|
@@ -111,13 +140,22 @@ startup.phase('tracing', 'Tracing', () => {
|
|
|
111
140
|
})
|
|
112
141
|
})
|
|
113
142
|
|
|
114
|
-
startup.
|
|
143
|
+
await startup.phaseAsync('database', 'Database', async (log) => {
|
|
115
144
|
const pool = initDatabase(config.database.url)
|
|
116
145
|
if (!pool) {
|
|
117
146
|
log.debug('DATABASE_URL not set — database features disabled')
|
|
118
147
|
return
|
|
119
148
|
}
|
|
120
149
|
|
|
150
|
+
// Fail fast if the database is behind on migrations, instead of letting a
|
|
151
|
+
// missing column surface as a cryptic SQL error mid-tool-call. The feature
|
|
152
|
+
// set mirrors what this server provisions: always `core`, plus `analysis`
|
|
153
|
+
// when vector storage is enabled. Module-independent — covers every pending
|
|
154
|
+
// migration, not just analysis ones.
|
|
155
|
+
const features: Feature[] = ['core']
|
|
156
|
+
if (config.analysis.enabled) features.push('analysis')
|
|
157
|
+
await assertMigrationsCurrent(pool, { features })
|
|
158
|
+
|
|
121
159
|
<% if (hasHttp && !useStaticTokenAuth) { -%>
|
|
122
160
|
_setAdapter(new PostgresqlAdapter({ pool }))
|
|
123
161
|
log.debug('OAuth token store connected')
|
|
@@ -1,3 +1,8 @@
|
|
|
1
1
|
# Token used by the framework's CRUD tools when calling your API backend.
|
|
2
2
|
# For local dev without a real backend, any non-empty value works.
|
|
3
3
|
ACCESS_TOKEN=demo-token
|
|
4
|
+
|
|
5
|
+
# Logging — the framework logger honors these at bootstrap (the simple preset
|
|
6
|
+
# doesn't use loadConfig). LOG_LEVEL=debug works ad-hoc when debugging.
|
|
7
|
+
# LOG_LEVEL=info # error | warn | info | debug
|
|
8
|
+
# LOG_FORMAT=json # text (default) | json
|