@nitrostack/cli 1.0.12 → 1.0.14
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/dist/commands/cursor.d.ts +11 -0
- package/dist/commands/cursor.d.ts.map +1 -0
- package/dist/commands/cursor.js +238 -0
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +82 -9
- package/dist/commands/upgrade.d.ts +12 -0
- package/dist/commands/upgrade.d.ts.map +1 -1
- package/dist/commands/upgrade.js +210 -106
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -0
- package/dist/skills/clone.d.ts +28 -0
- package/dist/skills/clone.d.ts.map +1 -0
- package/dist/skills/clone.js +60 -0
- package/dist/skills/detect-agents.d.ts +8 -0
- package/dist/skills/detect-agents.d.ts.map +1 -0
- package/dist/skills/detect-agents.js +129 -0
- package/dist/skills/discover.d.ts +12 -0
- package/dist/skills/discover.d.ts.map +1 -0
- package/dist/skills/discover.js +45 -0
- package/dist/skills/index.d.ts +21 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +97 -0
- package/dist/skills/installer.d.ts +21 -0
- package/dist/skills/installer.d.ts.map +1 -0
- package/dist/skills/installer.js +48 -0
- package/dist/skills/types.d.ts +39 -0
- package/dist/skills/types.d.ts.map +1 -0
- package/dist/skills/types.js +1 -0
- package/dist/skills/ui.d.ts +55 -0
- package/dist/skills/ui.d.ts.map +1 -0
- package/dist/skills/ui.js +102 -0
- package/package.json +3 -3
- package/templates/typescript-oauth/.env.example +71 -14
- package/templates/typescript-oauth/src/app.module.ts +7 -0
- package/templates/typescript-oauth/src/guards/oauth.guard.ts +19 -0
- package/templates/typescript-oauth/src/index.ts +9 -11
- package/templates/typescript-oauth/src/modules/flights/flights.prompts.ts +19 -1
- package/templates/typescript-oauth/src/services/duffel.service.ts +4 -2
- package/templates/typescript-pizzaz/.env.example +10 -0
- package/templates/typescript-starter/.env.example +10 -0
|
@@ -2,30 +2,87 @@
|
|
|
2
2
|
NITRO_LOG_LEVEL=info
|
|
3
3
|
NITROSTACK_APP_MODE=openai
|
|
4
4
|
|
|
5
|
-
#
|
|
5
|
+
# Server Transport Configuration (Optional)
|
|
6
6
|
# =============================================================================
|
|
7
|
-
#
|
|
7
|
+
# MCP_TRANSPORT_TYPE: Toggles transport mode. Values: stdio | http | dual.
|
|
8
|
+
# Defaults to 'stdio' in development and 'dual' in production/NODE_ENV=production.
|
|
8
9
|
# =============================================================================
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
10
|
+
# MCP_TRANSPORT_TYPE=dual
|
|
11
|
+
# PORT=3000
|
|
12
|
+
# HOST=localhost
|
|
13
|
+
# ENABLE_CORS=true
|
|
14
|
+
|
|
15
|
+
# Streamable HTTP Session Limits (Optional)
|
|
13
16
|
# =============================================================================
|
|
14
|
-
#
|
|
17
|
+
# Bounds memory against unauthenticated initialize floods. Defaults: 1000 sessions,
|
|
18
|
+
# 30-minute idle timeout. Only applies when running in http or dual transport mode.
|
|
15
19
|
# =============================================================================
|
|
20
|
+
# MCP_MAX_SESSIONS=1000
|
|
21
|
+
# MCP_SESSION_TIMEOUT_MS=1800000
|
|
22
|
+
|
|
23
|
+
# OAuth 2.1 MCP Server Configuration
|
|
24
|
+
# =============================================================================
|
|
25
|
+
# Enforcement Gate (Optional)
|
|
16
26
|
# =============================================================================
|
|
17
|
-
#
|
|
27
|
+
# OAUTH_REQUIRED controls whether authentication is enforced.
|
|
28
|
+
# - Unset / false (default): auth is NOT enforced. The server runs out-of-the-box
|
|
29
|
+
# and protected endpoints are reachable without a token. Best for local dev.
|
|
30
|
+
# - true: auth is enforced (fail-closed). If neither JWKS_URI nor
|
|
31
|
+
# INTROSPECTION_ENDPOINT is configured, the server STILL starts and logs a
|
|
32
|
+
# clear warning, but rejects all protected requests until a verifier is set.
|
|
33
|
+
# Set this to true (and configure a verifier below) before deploying.
|
|
34
|
+
# =============================================================================
|
|
35
|
+
# OAUTH_REQUIRED=true
|
|
36
|
+
|
|
37
|
+
# =============================================================================
|
|
38
|
+
# REQUIRED: Server Configuration
|
|
18
39
|
# =============================================================================
|
|
19
|
-
# After creating your API and Application in Auth0, fill in these values:
|
|
20
40
|
# Your Auth0 API Identifier (from APIs → MCP Server → Identifier)
|
|
21
41
|
# This MUST match exactly what you set when creating the API
|
|
22
|
-
# This MUST match exactly what you set when creating the API
|
|
23
42
|
RESOURCE_URI=https://mcplocal
|
|
24
|
-
|
|
43
|
+
|
|
44
|
+
# Your Auth0 tenant domain (authorization server URL)
|
|
25
45
|
AUTH_SERVER_URL=https://dev-5dt0utuk315713tjm.us.auth0.com
|
|
26
|
-
|
|
46
|
+
|
|
47
|
+
# Cryptographic JWKS Signature Verification (Recommended)
|
|
48
|
+
# =============================================================================
|
|
49
|
+
# If configured, the SDK cryptographically verifies token signatures using JWKS keys.
|
|
50
|
+
# Token validation is SECURE BY DEFAULT (fail-closed): if neither JWKS_URI nor an
|
|
51
|
+
# introspection endpoint (below) is configured, ALL tokens are rejected. Configure
|
|
52
|
+
# one of them for a working server.
|
|
53
|
+
# NOTE: Unsigned/signature-less token decoding is disabled by default and is only
|
|
54
|
+
# available via the in-code `allowInsecureTokenDecode: true` option in
|
|
55
|
+
# OAuthModule.forRoot(...) — intended for local development only, never production.
|
|
56
|
+
# =============================================================================
|
|
57
|
+
# JWKS_URI=https://dev-5dt0utuk315713tjm.us.auth0.com/.well-known/jwks.json
|
|
58
|
+
|
|
59
|
+
# Expected token validation audience (should match RESOURCE_URI)
|
|
27
60
|
TOKEN_AUDIENCE=https://mcplocal
|
|
28
|
-
|
|
61
|
+
|
|
62
|
+
# Expected token validation issuer (your authorization server tenant domain)
|
|
29
63
|
TOKEN_ISSUER=https://dev-5dt0utuk315713tjm.us.auth0.com
|
|
30
64
|
|
|
31
|
-
|
|
65
|
+
# Token Introspection Configuration (Alternative to JWKS signature verification)
|
|
66
|
+
# =============================================================================
|
|
67
|
+
# INTROSPECTION_ENDPOINT=https://dev-5dt0utuk315713tjm.us.auth0.com/oauth/introspect
|
|
68
|
+
# INTROSPECTION_CLIENT_ID=your-introspection-client-id
|
|
69
|
+
# INTROSPECTION_CLIENT_SECRET=your-introspection-client-secret
|
|
70
|
+
|
|
71
|
+
# OAuth Discovery Settings (Optional)
|
|
72
|
+
# =============================================================================
|
|
73
|
+
# OAUTH_DISCOVERY_PORT=3005
|
|
74
|
+
# OAUTH_DISCOVERY_AUTO_RETRY=true
|
|
75
|
+
# MCP_SERVER_PORT=3000
|
|
76
|
+
|
|
77
|
+
# Dynamic Client Registration (Optional / disabled by default)
|
|
78
|
+
# =============================================================================
|
|
79
|
+
# Set to 'true' to expose the /oauth/v2/register endpoint. It only serves the
|
|
80
|
+
# statically configured client below; without OAUTH_CLIENT_ID it stays disabled.
|
|
81
|
+
# =============================================================================
|
|
82
|
+
# OAUTH_ENABLE_CLIENT_REGISTRATION=true
|
|
83
|
+
# OAUTH_CLIENT_ID=your-client-id
|
|
84
|
+
# OAUTH_CLIENT_SECRET=your-client-secret
|
|
85
|
+
|
|
86
|
+
# Duffel API Integration (Required for Flight Search & Booking)
|
|
87
|
+
# =============================================================================
|
|
88
|
+
DUFFEL_API_KEY=your-duffel-api-key
|
|
@@ -36,6 +36,13 @@ import { SystemHealthCheck } from './health/system.health.js';
|
|
|
36
36
|
|
|
37
37
|
// Enable OAuth 2.1 authentication
|
|
38
38
|
OAuthModule.forRoot({
|
|
39
|
+
// Whether OAuth is enforced. Defaults to false (dev-friendly): the server
|
|
40
|
+
// runs out-of-the-box and protected endpoints are reachable without a token.
|
|
41
|
+
// Set OAUTH_REQUIRED=true to enforce auth (fail-closed). When enforced but no
|
|
42
|
+
// verifier (JWKS_URI / INTROSPECTION_ENDPOINT) is configured, the server still
|
|
43
|
+
// starts and warns, but rejects protected requests until one is configured.
|
|
44
|
+
required: process.env.OAUTH_REQUIRED === 'true',
|
|
45
|
+
|
|
39
46
|
// Resource URI - YOUR MCP server's public URL
|
|
40
47
|
// This is used for token audience binding (RFC 8707)
|
|
41
48
|
// CRITICAL: Tokens must be issued specifically for this URI
|
|
@@ -41,6 +41,25 @@ export class OAuthGuard implements Guard {
|
|
|
41
41
|
} else if (metaToken) {
|
|
42
42
|
token = metaToken as string;
|
|
43
43
|
}
|
|
44
|
+
|
|
45
|
+
// Enforcement gate: when OAuth is not required (OAUTH_REQUIRED not "true"),
|
|
46
|
+
// do not reject. Best-effort: if a valid token happens to be present, attach
|
|
47
|
+
// its identity; otherwise allow the request through unauthenticated.
|
|
48
|
+
if (!OAuthModule.isAuthRequired()) {
|
|
49
|
+
if (token) {
|
|
50
|
+
const result = await OAuthModule.validateToken(token);
|
|
51
|
+
if (result.valid) {
|
|
52
|
+
const payload = result.payload as OAuthTokenPayload;
|
|
53
|
+
context.auth = {
|
|
54
|
+
subject: payload.sub,
|
|
55
|
+
scopes: this.extractScopes(payload),
|
|
56
|
+
clientId: payload.client_id,
|
|
57
|
+
tokenPayload: payload,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
44
63
|
|
|
45
64
|
if (!token) {
|
|
46
65
|
throw new Error(
|
|
@@ -28,26 +28,24 @@ async function bootstrap() {
|
|
|
28
28
|
try {
|
|
29
29
|
console.error('🔐 Starting Calculator MCP Server with OAuth 2.1...\\n');
|
|
30
30
|
|
|
31
|
-
// Validate required environment variables for OAuth
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
missing.forEach(v => console.error(` - ${v}`));
|
|
38
|
-
console.error('\\n💡 Copy .env.example to .env and configure your OAuth provider');
|
|
39
|
-
console.error(' Or check the test-oauth/.env for reference\\n');
|
|
40
|
-
process.exit(1);
|
|
31
|
+
// Validate required environment variables for OAuth, set defaults if missing
|
|
32
|
+
if (!process.env.RESOURCE_URI || !process.env.AUTH_SERVER_URL) {
|
|
33
|
+
console.error('⚠️ Warning: Missing RESOURCE_URI or AUTH_SERVER_URL environment variables.');
|
|
34
|
+
console.error(' Defaulting to local test endpoints. Copy .env.example to .env to configure.\n');
|
|
35
|
+
process.env.RESOURCE_URI = process.env.RESOURCE_URI || 'http://localhost:3000';
|
|
36
|
+
process.env.AUTH_SERVER_URL = process.env.AUTH_SERVER_URL || 'http://localhost:8080/auth';
|
|
41
37
|
}
|
|
42
38
|
|
|
43
39
|
// Create the MCP application
|
|
44
40
|
const server = await McpApplicationFactory.create(AppModule);
|
|
45
41
|
|
|
42
|
+
const authEnforced = process.env.OAUTH_REQUIRED === 'true';
|
|
46
43
|
console.error('✅ OAuth 2.1 Module configured');
|
|
47
44
|
console.error(` Resource URI: ${process.env.RESOURCE_URI}`);
|
|
48
45
|
console.error(` Auth Server: ${process.env.AUTH_SERVER_URL}`);
|
|
49
46
|
console.error(` Scopes: read, write, admin`);
|
|
50
|
-
console.error(` Audience: ${process.env.TOKEN_AUDIENCE || process.env.RESOURCE_URI}
|
|
47
|
+
console.error(` Audience: ${process.env.TOKEN_AUDIENCE || process.env.RESOURCE_URI}`);
|
|
48
|
+
console.error(` Enforcement: ${authEnforced ? 'ON (OAUTH_REQUIRED=true)' : 'OFF (dev mode — set OAUTH_REQUIRED=true to enforce)'}\\n`);
|
|
51
49
|
|
|
52
50
|
// Start the server
|
|
53
51
|
await server.start();
|
|
@@ -79,8 +79,26 @@ Respond to EXACTLY what the user asked - nothing more.`;
|
|
|
79
79
|
]
|
|
80
80
|
})
|
|
81
81
|
async flightComparison(input: any, ctx: ExecutionContext) {
|
|
82
|
+
let ids: string[] = [];
|
|
83
|
+
if (Array.isArray(input.offerIds)) {
|
|
84
|
+
ids = input.offerIds;
|
|
85
|
+
} else if (typeof input.offerIds === 'string') {
|
|
86
|
+
const trimmed = input.offerIds.trim();
|
|
87
|
+
if (trimmed.startsWith('[') && trimmed.endsWith(']')) {
|
|
88
|
+
try {
|
|
89
|
+
const parsed = JSON.parse(trimmed);
|
|
90
|
+
ids = Array.isArray(parsed) ? parsed : [parsed];
|
|
91
|
+
} catch {
|
|
92
|
+
ids = trimmed.split(',').map((s: string) => s.trim());
|
|
93
|
+
}
|
|
94
|
+
} else {
|
|
95
|
+
ids = trimmed.split(',').map((s: string) => s.trim());
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
ids = ids.filter(Boolean);
|
|
99
|
+
|
|
82
100
|
const offers = await Promise.all(
|
|
83
|
-
|
|
101
|
+
ids.map((id: string) => this.duffelService.getOffer(id))
|
|
84
102
|
);
|
|
85
103
|
|
|
86
104
|
const comparisonData = offers.map((offer: any) => {
|
|
@@ -12,9 +12,11 @@ export class DuffelService {
|
|
|
12
12
|
private duffel: Duffel;
|
|
13
13
|
|
|
14
14
|
constructor() {
|
|
15
|
-
|
|
15
|
+
let apiKey = process.env.DUFFEL_API_KEY;
|
|
16
16
|
if (!apiKey) {
|
|
17
|
-
|
|
17
|
+
console.error('⚠️ Warning: DUFFEL_API_KEY environment variable is missing.');
|
|
18
|
+
console.error(' Running with a dummy key for testing/dry-run mode.\n');
|
|
19
|
+
apiKey = 'duffel_test_dummy_key';
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
this.duffel = new Duffel({
|
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
NITRO_LOG_LEVEL=info
|
|
3
3
|
NITROSTACK_APP_MODE=openai
|
|
4
4
|
|
|
5
|
+
# Server Transport Configuration (Optional)
|
|
6
|
+
# =============================================================================
|
|
7
|
+
# MCP_TRANSPORT_TYPE: Toggles transport mode. Values: stdio | http | dual.
|
|
8
|
+
# Defaults to 'stdio' in development and 'dual' in production/NODE_ENV=production.
|
|
9
|
+
# =============================================================================
|
|
10
|
+
# MCP_TRANSPORT_TYPE=stdio
|
|
11
|
+
# PORT=3000
|
|
12
|
+
# HOST=localhost
|
|
13
|
+
# ENABLE_CORS=true
|
|
14
|
+
|
|
5
15
|
# Mapbox Configuration (Optional)
|
|
6
16
|
# =============================================================================
|
|
7
17
|
# The map widget uses Mapbox GL for interactive maps.
|
|
@@ -1,3 +1,13 @@
|
|
|
1
1
|
# NitroStack Configuration
|
|
2
2
|
NITRO_LOG_LEVEL=info
|
|
3
3
|
NITROSTACK_APP_MODE=openai
|
|
4
|
+
|
|
5
|
+
# Server Transport Configuration (Optional)
|
|
6
|
+
# =============================================================================
|
|
7
|
+
# MCP_TRANSPORT_TYPE: Toggles transport mode. Values: stdio | http | dual.
|
|
8
|
+
# Defaults to 'stdio' in development and 'dual' in production/NODE_ENV=production.
|
|
9
|
+
# =============================================================================
|
|
10
|
+
# MCP_TRANSPORT_TYPE=stdio
|
|
11
|
+
# PORT=3000
|
|
12
|
+
# HOST=localhost
|
|
13
|
+
# ENABLE_CORS=true
|