nitrostack 1.0.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.
Files changed (290) hide show
  1. package/CHANGELOG.md +227 -0
  2. package/CONTRIBUTING.md +182 -0
  3. package/LICENSE +201 -0
  4. package/LICENSE_URLS_UPDATE_COMPLETE.md +388 -0
  5. package/NOTICE +153 -0
  6. package/README.md +571 -0
  7. package/dist/auth/api-key.d.ts +118 -0
  8. package/dist/auth/api-key.d.ts.map +1 -0
  9. package/dist/auth/api-key.js +168 -0
  10. package/dist/auth/api-key.js.map +1 -0
  11. package/dist/auth/client.d.ts +151 -0
  12. package/dist/auth/client.d.ts.map +1 -0
  13. package/dist/auth/client.js +330 -0
  14. package/dist/auth/client.js.map +1 -0
  15. package/dist/auth/index.d.ts +30 -0
  16. package/dist/auth/index.d.ts.map +1 -0
  17. package/dist/auth/index.js +43 -0
  18. package/dist/auth/index.js.map +1 -0
  19. package/dist/auth/middleware.d.ts +95 -0
  20. package/dist/auth/middleware.d.ts.map +1 -0
  21. package/dist/auth/middleware.js +260 -0
  22. package/dist/auth/middleware.js.map +1 -0
  23. package/dist/auth/pkce.d.ts +53 -0
  24. package/dist/auth/pkce.d.ts.map +1 -0
  25. package/dist/auth/pkce.js +105 -0
  26. package/dist/auth/pkce.js.map +1 -0
  27. package/dist/auth/quick-setup.d.ts +94 -0
  28. package/dist/auth/quick-setup.d.ts.map +1 -0
  29. package/dist/auth/quick-setup.js +210 -0
  30. package/dist/auth/quick-setup.js.map +1 -0
  31. package/dist/auth/server-integration.d.ts +97 -0
  32. package/dist/auth/server-integration.d.ts.map +1 -0
  33. package/dist/auth/server-integration.js +182 -0
  34. package/dist/auth/server-integration.js.map +1 -0
  35. package/dist/auth/server-metadata.d.ts +51 -0
  36. package/dist/auth/server-metadata.d.ts.map +1 -0
  37. package/dist/auth/server-metadata.js +106 -0
  38. package/dist/auth/server-metadata.js.map +1 -0
  39. package/dist/auth/simple-jwt.d.ts +88 -0
  40. package/dist/auth/simple-jwt.d.ts.map +1 -0
  41. package/dist/auth/simple-jwt.js +152 -0
  42. package/dist/auth/simple-jwt.js.map +1 -0
  43. package/dist/auth/token-store.d.ts +104 -0
  44. package/dist/auth/token-store.d.ts.map +1 -0
  45. package/dist/auth/token-store.js +205 -0
  46. package/dist/auth/token-store.js.map +1 -0
  47. package/dist/auth/token-validation.d.ts +47 -0
  48. package/dist/auth/token-validation.d.ts.map +1 -0
  49. package/dist/auth/token-validation.js +237 -0
  50. package/dist/auth/token-validation.js.map +1 -0
  51. package/dist/auth/types.d.ts +215 -0
  52. package/dist/auth/types.d.ts.map +1 -0
  53. package/dist/auth/types.js +6 -0
  54. package/dist/auth/types.js.map +1 -0
  55. package/dist/cli/commands/build.d.ts +6 -0
  56. package/dist/cli/commands/build.d.ts.map +1 -0
  57. package/dist/cli/commands/build.js +104 -0
  58. package/dist/cli/commands/build.js.map +1 -0
  59. package/dist/cli/commands/dev.d.ts +7 -0
  60. package/dist/cli/commands/dev.d.ts.map +1 -0
  61. package/dist/cli/commands/dev.js +312 -0
  62. package/dist/cli/commands/dev.js.map +1 -0
  63. package/dist/cli/commands/generate-types.d.ts +8 -0
  64. package/dist/cli/commands/generate-types.d.ts.map +1 -0
  65. package/dist/cli/commands/generate-types.js +220 -0
  66. package/dist/cli/commands/generate-types.js.map +1 -0
  67. package/dist/cli/commands/generate.d.ts +5 -0
  68. package/dist/cli/commands/generate.d.ts.map +1 -0
  69. package/dist/cli/commands/generate.js +365 -0
  70. package/dist/cli/commands/generate.js.map +1 -0
  71. package/dist/cli/commands/init.d.ts +7 -0
  72. package/dist/cli/commands/init.d.ts.map +1 -0
  73. package/dist/cli/commands/init.js +365 -0
  74. package/dist/cli/commands/init.js.map +1 -0
  75. package/dist/cli/commands/start.d.ts +6 -0
  76. package/dist/cli/commands/start.d.ts.map +1 -0
  77. package/dist/cli/commands/start.js +61 -0
  78. package/dist/cli/commands/start.js.map +1 -0
  79. package/dist/cli/index.d.ts +3 -0
  80. package/dist/cli/index.d.ts.map +1 -0
  81. package/dist/cli/index.js +47 -0
  82. package/dist/cli/index.js.map +1 -0
  83. package/dist/cli/mcp-dev-wrapper.d.ts +3 -0
  84. package/dist/cli/mcp-dev-wrapper.d.ts.map +1 -0
  85. package/dist/cli/mcp-dev-wrapper.js +116 -0
  86. package/dist/cli/mcp-dev-wrapper.js.map +1 -0
  87. package/dist/core/apikey-module.d.ts +69 -0
  88. package/dist/core/apikey-module.d.ts.map +1 -0
  89. package/dist/core/apikey-module.js +114 -0
  90. package/dist/core/apikey-module.js.map +1 -0
  91. package/dist/core/app-decorator.d.ts +58 -0
  92. package/dist/core/app-decorator.d.ts.map +1 -0
  93. package/dist/core/app-decorator.js +261 -0
  94. package/dist/core/app-decorator.js.map +1 -0
  95. package/dist/core/builders.d.ts +38 -0
  96. package/dist/core/builders.d.ts.map +1 -0
  97. package/dist/core/builders.js +129 -0
  98. package/dist/core/builders.js.map +1 -0
  99. package/dist/core/component.d.ts +105 -0
  100. package/dist/core/component.d.ts.map +1 -0
  101. package/dist/core/component.js +182 -0
  102. package/dist/core/component.js.map +1 -0
  103. package/dist/core/config-module.d.ts +55 -0
  104. package/dist/core/config-module.d.ts.map +1 -0
  105. package/dist/core/config-module.js +94 -0
  106. package/dist/core/config-module.js.map +1 -0
  107. package/dist/core/decorators/cache.decorator.d.ts +61 -0
  108. package/dist/core/decorators/cache.decorator.d.ts.map +1 -0
  109. package/dist/core/decorators/cache.decorator.js +115 -0
  110. package/dist/core/decorators/cache.decorator.js.map +1 -0
  111. package/dist/core/decorators/health-check.decorator.d.ts +80 -0
  112. package/dist/core/decorators/health-check.decorator.d.ts.map +1 -0
  113. package/dist/core/decorators/health-check.decorator.js +153 -0
  114. package/dist/core/decorators/health-check.decorator.js.map +1 -0
  115. package/dist/core/decorators/rate-limit.decorator.d.ts +62 -0
  116. package/dist/core/decorators/rate-limit.decorator.d.ts.map +1 -0
  117. package/dist/core/decorators/rate-limit.decorator.js +129 -0
  118. package/dist/core/decorators/rate-limit.decorator.js.map +1 -0
  119. package/dist/core/decorators.d.ts +151 -0
  120. package/dist/core/decorators.d.ts.map +1 -0
  121. package/dist/core/decorators.js +142 -0
  122. package/dist/core/decorators.js.map +1 -0
  123. package/dist/core/di/container.d.ts +42 -0
  124. package/dist/core/di/container.d.ts.map +1 -0
  125. package/dist/core/di/container.js +76 -0
  126. package/dist/core/di/container.js.map +1 -0
  127. package/dist/core/di/injectable.decorator.d.ts +35 -0
  128. package/dist/core/di/injectable.decorator.d.ts.map +1 -0
  129. package/dist/core/di/injectable.decorator.js +57 -0
  130. package/dist/core/di/injectable.decorator.js.map +1 -0
  131. package/dist/core/errors.d.ts +54 -0
  132. package/dist/core/errors.d.ts.map +1 -0
  133. package/dist/core/errors.js +87 -0
  134. package/dist/core/errors.js.map +1 -0
  135. package/dist/core/events/event-emitter.d.ts +50 -0
  136. package/dist/core/events/event-emitter.d.ts.map +1 -0
  137. package/dist/core/events/event-emitter.js +94 -0
  138. package/dist/core/events/event-emitter.js.map +1 -0
  139. package/dist/core/events/event.decorator.d.ts +48 -0
  140. package/dist/core/events/event.decorator.d.ts.map +1 -0
  141. package/dist/core/events/event.decorator.js +68 -0
  142. package/dist/core/events/event.decorator.js.map +1 -0
  143. package/dist/core/filters/exception-filter.decorator.d.ts +40 -0
  144. package/dist/core/filters/exception-filter.decorator.d.ts.map +1 -0
  145. package/dist/core/filters/exception-filter.decorator.js +54 -0
  146. package/dist/core/filters/exception-filter.decorator.js.map +1 -0
  147. package/dist/core/filters/exception-filter.interface.d.ts +30 -0
  148. package/dist/core/filters/exception-filter.interface.d.ts.map +1 -0
  149. package/dist/core/filters/exception-filter.interface.js +2 -0
  150. package/dist/core/filters/exception-filter.interface.js.map +1 -0
  151. package/dist/core/guards/apikey.guard.d.ts +22 -0
  152. package/dist/core/guards/apikey.guard.d.ts.map +1 -0
  153. package/dist/core/guards/apikey.guard.js +11 -0
  154. package/dist/core/guards/apikey.guard.js.map +1 -0
  155. package/dist/core/guards/guard.interface.d.ts +18 -0
  156. package/dist/core/guards/guard.interface.d.ts.map +1 -0
  157. package/dist/core/guards/guard.interface.js +2 -0
  158. package/dist/core/guards/guard.interface.js.map +1 -0
  159. package/dist/core/guards/jwt.guard.d.ts +18 -0
  160. package/dist/core/guards/jwt.guard.d.ts.map +1 -0
  161. package/dist/core/guards/jwt.guard.js +2 -0
  162. package/dist/core/guards/jwt.guard.js.map +1 -0
  163. package/dist/core/guards/oauth.guard.d.ts +35 -0
  164. package/dist/core/guards/oauth.guard.d.ts.map +1 -0
  165. package/dist/core/guards/oauth.guard.js +2 -0
  166. package/dist/core/guards/oauth.guard.js.map +1 -0
  167. package/dist/core/guards/use-guards.decorator.d.ts +25 -0
  168. package/dist/core/guards/use-guards.decorator.d.ts.map +1 -0
  169. package/dist/core/guards/use-guards.decorator.js +32 -0
  170. package/dist/core/guards/use-guards.decorator.js.map +1 -0
  171. package/dist/core/health/health-checks.resource.d.ts +14 -0
  172. package/dist/core/health/health-checks.resource.d.ts.map +1 -0
  173. package/dist/core/health/health-checks.resource.js +29 -0
  174. package/dist/core/health/health-checks.resource.js.map +1 -0
  175. package/dist/core/index.d.ts +55 -0
  176. package/dist/core/index.d.ts.map +1 -0
  177. package/dist/core/index.js +57 -0
  178. package/dist/core/index.js.map +1 -0
  179. package/dist/core/interceptors/interceptor.decorator.d.ts +37 -0
  180. package/dist/core/interceptors/interceptor.decorator.d.ts.map +1 -0
  181. package/dist/core/interceptors/interceptor.decorator.js +51 -0
  182. package/dist/core/interceptors/interceptor.decorator.js.map +1 -0
  183. package/dist/core/interceptors/interceptor.interface.d.ts +31 -0
  184. package/dist/core/interceptors/interceptor.interface.d.ts.map +1 -0
  185. package/dist/core/interceptors/interceptor.interface.js +2 -0
  186. package/dist/core/interceptors/interceptor.interface.js.map +1 -0
  187. package/dist/core/jwt-module.d.ts +51 -0
  188. package/dist/core/jwt-module.d.ts.map +1 -0
  189. package/dist/core/jwt-module.js +52 -0
  190. package/dist/core/jwt-module.js.map +1 -0
  191. package/dist/core/logger.d.ts +18 -0
  192. package/dist/core/logger.d.ts.map +1 -0
  193. package/dist/core/logger.js +51 -0
  194. package/dist/core/logger.js.map +1 -0
  195. package/dist/core/middleware/middleware.decorator.d.ts +39 -0
  196. package/dist/core/middleware/middleware.decorator.d.ts.map +1 -0
  197. package/dist/core/middleware/middleware.decorator.js +53 -0
  198. package/dist/core/middleware/middleware.decorator.js.map +1 -0
  199. package/dist/core/middleware/middleware.interface.d.ts +29 -0
  200. package/dist/core/middleware/middleware.interface.d.ts.map +1 -0
  201. package/dist/core/middleware/middleware.interface.js +2 -0
  202. package/dist/core/middleware/middleware.interface.js.map +1 -0
  203. package/dist/core/module.d.ts +74 -0
  204. package/dist/core/module.d.ts.map +1 -0
  205. package/dist/core/module.js +82 -0
  206. package/dist/core/module.js.map +1 -0
  207. package/dist/core/oauth-module.d.ts +144 -0
  208. package/dist/core/oauth-module.d.ts.map +1 -0
  209. package/dist/core/oauth-module.js +190 -0
  210. package/dist/core/oauth-module.js.map +1 -0
  211. package/dist/core/pipes/pipe.decorator.d.ts +55 -0
  212. package/dist/core/pipes/pipe.decorator.d.ts.map +1 -0
  213. package/dist/core/pipes/pipe.decorator.js +85 -0
  214. package/dist/core/pipes/pipe.decorator.js.map +1 -0
  215. package/dist/core/pipes/pipe.interface.d.ts +36 -0
  216. package/dist/core/pipes/pipe.interface.d.ts.map +1 -0
  217. package/dist/core/pipes/pipe.interface.js +2 -0
  218. package/dist/core/pipes/pipe.interface.js.map +1 -0
  219. package/dist/core/prompt.d.ts +37 -0
  220. package/dist/core/prompt.d.ts.map +1 -0
  221. package/dist/core/prompt.js +76 -0
  222. package/dist/core/prompt.js.map +1 -0
  223. package/dist/core/resource.d.ts +42 -0
  224. package/dist/core/resource.d.ts.map +1 -0
  225. package/dist/core/resource.js +90 -0
  226. package/dist/core/resource.js.map +1 -0
  227. package/dist/core/server.d.ts +72 -0
  228. package/dist/core/server.d.ts.map +1 -0
  229. package/dist/core/server.js +406 -0
  230. package/dist/core/server.js.map +1 -0
  231. package/dist/core/tool.d.ts +78 -0
  232. package/dist/core/tool.d.ts.map +1 -0
  233. package/dist/core/tool.js +190 -0
  234. package/dist/core/tool.js.map +1 -0
  235. package/dist/core/transports/http-server.d.ts +102 -0
  236. package/dist/core/transports/http-server.d.ts.map +1 -0
  237. package/dist/core/transports/http-server.js +265 -0
  238. package/dist/core/transports/http-server.js.map +1 -0
  239. package/dist/core/types.d.ts +123 -0
  240. package/dist/core/types.d.ts.map +1 -0
  241. package/dist/core/types.js +2 -0
  242. package/dist/core/types.js.map +1 -0
  243. package/dist/core/widgets/widget-examples.resource.d.ts +17 -0
  244. package/dist/core/widgets/widget-examples.resource.d.ts.map +1 -0
  245. package/dist/core/widgets/widget-examples.resource.js +28 -0
  246. package/dist/core/widgets/widget-examples.resource.js.map +1 -0
  247. package/dist/core/widgets/widget-registry.d.ts +56 -0
  248. package/dist/core/widgets/widget-registry.d.ts.map +1 -0
  249. package/dist/core/widgets/widget-registry.js +75 -0
  250. package/dist/core/widgets/widget-registry.js.map +1 -0
  251. package/dist/testing/index.d.ts +82 -0
  252. package/dist/testing/index.d.ts.map +1 -0
  253. package/dist/testing/index.js +164 -0
  254. package/dist/testing/index.js.map +1 -0
  255. package/dist/ui-next/index.d.ts +31 -0
  256. package/dist/ui-next/index.d.ts.map +1 -0
  257. package/dist/ui-next/index.js +687 -0
  258. package/dist/ui-next/index.js.map +1 -0
  259. package/dist/widgets/index.d.ts +9 -0
  260. package/dist/widgets/index.d.ts.map +1 -0
  261. package/dist/widgets/index.js +9 -0
  262. package/dist/widgets/index.js.map +1 -0
  263. package/dist/widgets/metadata.d.ts +53 -0
  264. package/dist/widgets/metadata.d.ts.map +1 -0
  265. package/dist/widgets/metadata.js +29 -0
  266. package/dist/widgets/metadata.js.map +1 -0
  267. package/dist/widgets/withToolData.d.ts +19 -0
  268. package/dist/widgets/withToolData.d.ts.map +1 -0
  269. package/dist/widgets/withToolData.js +240 -0
  270. package/dist/widgets/withToolData.js.map +1 -0
  271. package/jest.config.js +21 -0
  272. package/package.json +108 -0
  273. package/templates/typescript-auth/AI_AGENT_CLI_REFERENCE.md +702 -0
  274. package/templates/typescript-auth/AI_AGENT_SDK_REFERENCE.md +1260 -0
  275. package/templates/typescript-auth/README.md +400 -0
  276. package/templates/typescript-auth/package.json +44 -0
  277. package/templates/typescript-auth-api-key/AI_AGENT_CLI_REFERENCE.md +701 -0
  278. package/templates/typescript-auth-api-key/AI_AGENT_SDK_REFERENCE.md +1260 -0
  279. package/templates/typescript-auth-api-key/README.md +483 -0
  280. package/templates/typescript-auth-api-key/package-lock.json +124 -0
  281. package/templates/typescript-auth-api-key/package.json +29 -0
  282. package/templates/typescript-oauth/AI_AGENT_CLI_REFERENCE.md +701 -0
  283. package/templates/typescript-oauth/AI_AGENT_SDK_REFERENCE.md +1260 -0
  284. package/templates/typescript-oauth/OAUTH_SETUP.md +406 -0
  285. package/templates/typescript-oauth/README.md +350 -0
  286. package/templates/typescript-oauth/package.json +30 -0
  287. package/templates/typescript-starter/AI_AGENT_CLI_REFERENCE.md +701 -0
  288. package/templates/typescript-starter/AI_AGENT_SDK_REFERENCE.md +1260 -0
  289. package/templates/typescript-starter/README.md +312 -0
  290. package/templates/typescript-starter/package.json +32 -0
@@ -0,0 +1,483 @@
1
+ # API Key Authentication MCP Server
2
+
3
+ A complete example of building an MCP server with **API key authentication** using NitroStack.
4
+
5
+ ## 🎯 What You'll Learn
6
+
7
+ - ✅ How to add API key authentication to your MCP server
8
+ - ✅ How to create public and protected tools
9
+ - ✅ How to use `ApiKeyModule` and `ApiKeyGuard`
10
+ - ✅ How to test API key auth in NitroStack Studio
11
+ - ✅ How to combine JWT and API key authentication (multi-auth)
12
+
13
+ ## 🔑 Test API Keys
14
+
15
+ This template provides **test API keys** for immediate testing:
16
+
17
+ ```
18
+ sk_test_public_demo_key_12345
19
+ sk_test_admin_demo_key_67890
20
+ ```
21
+
22
+ ⚠️ **Important**: These are demo keys only. Never use them in production!
23
+
24
+ ## 📦 Installation
25
+
26
+ ```bash
27
+ # Install dependencies
28
+ npm install
29
+
30
+ # Build the project
31
+ npm run build
32
+
33
+ # Run in development mode
34
+ npm run dev
35
+ ```
36
+
37
+ ## 🚀 Quick Start
38
+
39
+ ### 1. Start the Server
40
+
41
+ ```bash
42
+ npm run build
43
+ nitrostack dev
44
+ ```
45
+
46
+ The server will start with API key authentication enabled.
47
+
48
+ ### 2. Open NitroStack Studio
49
+
50
+ Navigate to `http://localhost:3000` (Studio should auto-open)
51
+
52
+ ### 3. Set Your API Key
53
+
54
+ 1. Go to **Auth** tab in Studio
55
+ 2. Find the **API Key** section
56
+ 3. Paste one of the test keys:
57
+ ```
58
+ sk_test_public_demo_key_12345
59
+ ```
60
+ 4. Click **Set Key**
61
+
62
+ ### 4. Test the Tools
63
+
64
+ #### Try a Public Tool (No Auth Required)
65
+ 1. Go to **Tools** tab
66
+ 2. Select `get_public_info`
67
+ 3. Enter any topic
68
+ 4. Execute ✓ - Works without API key!
69
+
70
+ #### Try a Protected Tool (Auth Required)
71
+ 1. Select `get_protected_data`
72
+ 2. Choose data type: `user`, `account`, or `settings`
73
+ 3. Execute ✓ - Works with valid API key!
74
+ 4. Try clearing your API key → You'll get an authentication error
75
+
76
+ ## 🏗️ Project Structure
77
+
78
+ ```
79
+ typescript-auth-api-key/
80
+ ├── src/
81
+ │ ├── guards/
82
+ │ │ └── apikey.guard.ts # API key validation guard
83
+ │ ├── modules/
84
+ │ │ └── demo/
85
+ │ │ ├── demo.module.ts # Demo module
86
+ │ │ └── demo.tools.ts # Example tools
87
+ │ ├── app.module.ts # Root module
88
+ │ └── index.ts # Main entry point (ApiKeyModule setup)
89
+ ├── .env # Test API keys
90
+ ├── package.json
91
+ ├── tsconfig.json
92
+ └── README.md
93
+ ```
94
+
95
+ ## 🛡️ How API Key Auth Works
96
+
97
+ ### 1. Configure ApiKeyModule
98
+
99
+ In `src/index.ts`:
100
+
101
+ ```typescript
102
+ const app = await McpApplicationFactory.create(AppModule, {
103
+ // Enable API key authentication
104
+ apiKey: ApiKeyModule.forRoot({
105
+ keysEnvPrefix: 'API_KEY', // Reads API_KEY_1, API_KEY_2, etc.
106
+ headerName: 'x-api-key',
107
+ metadataField: 'apiKey',
108
+ }),
109
+ });
110
+ ```
111
+
112
+ ### 2. Create an API Key Guard
113
+
114
+ In `src/guards/apikey.guard.ts`:
115
+
116
+ ```typescript
117
+ export class ApiKeyGuard implements Guard {
118
+ async canActivate(context: ExecutionContext): Promise<boolean> {
119
+ const apiKey = context.metadata?.apiKey;
120
+
121
+ if (!apiKey) {
122
+ throw new Error('API key required');
123
+ }
124
+
125
+ const isValid = await ApiKeyModule.validate(apiKey);
126
+
127
+ if (!isValid) {
128
+ throw new Error('Invalid API key');
129
+ }
130
+
131
+ context.auth = {
132
+ subject: `apikey_${apiKey.substring(0, 12)}`,
133
+ scopes: ['*'],
134
+ };
135
+
136
+ return true;
137
+ }
138
+ }
139
+ ```
140
+
141
+ ### 3. Protect Your Tools
142
+
143
+ ```typescript
144
+ @Injectable()
145
+ export class DemoTools {
146
+
147
+ // PUBLIC: Anyone can call
148
+ @Tool({ name: 'get_public_info' })
149
+ async getPublicInfo() {
150
+ return { data: 'public' };
151
+ }
152
+
153
+ // PROTECTED: Requires API key
154
+ @Tool({ name: 'get_protected_data' })
155
+ @UseGuards(ApiKeyGuard) // 🔒 Protected!
156
+ async getProtectedData() {
157
+ return { data: 'protected' };
158
+ }
159
+ }
160
+ ```
161
+
162
+ ## 🔐 API Key Management
163
+
164
+ ### Environment Variables
165
+
166
+ API keys are loaded from environment variables:
167
+
168
+ ```bash
169
+ # .env
170
+ API_KEY_1=sk_test_public_demo_key_12345
171
+ API_KEY_2=sk_test_admin_demo_key_67890
172
+ API_KEY_3=your_custom_key_here
173
+ ```
174
+
175
+ The `ApiKeyModule` automatically reads all `API_KEY_*` variables.
176
+
177
+ ### Studio Integration
178
+
179
+ NitroStack Studio provides a **dedicated API Key UI**:
180
+
181
+ 1. **Auth Tab** → **API Key** section
182
+ 2. Enter your API key
183
+ 3. It's automatically included in all tool calls
184
+ 4. Persists across page refreshes
185
+ 5. Clear button to reset
186
+
187
+ ### How Keys Are Sent
188
+
189
+ When you execute a tool in Studio, the API key is sent in the `_meta` field:
190
+
191
+ ```javascript
192
+ {
193
+ args: { /* your tool arguments */ },
194
+ _meta: {
195
+ apiKey: "sk_test_public_demo_key_12345",
196
+ "x-api-key": "sk_test_public_demo_key_12345"
197
+ }
198
+ }
199
+ ```
200
+
201
+ The guard extracts it and validates it.
202
+
203
+ ## 🔄 Multi-Auth Example (JWT + API Key)
204
+
205
+ You can use **both JWT and API key** authentication together!
206
+
207
+ ### Example: JWT Guard + API Key Guard
208
+
209
+ ```typescript
210
+ // Guard that accepts EITHER JWT OR API Key
211
+ export class MultiAuthGuard implements Guard {
212
+ async canActivate(context: ExecutionContext): Promise<boolean> {
213
+ // Try JWT first
214
+ const jwt = context.metadata?._jwt || context.metadata?.authorization;
215
+ if (jwt) {
216
+ // Validate JWT...
217
+ return true;
218
+ }
219
+
220
+ // Try API key
221
+ const apiKey = context.metadata?.apiKey;
222
+ if (apiKey) {
223
+ const isValid = await ApiKeyModule.validate(apiKey);
224
+ return isValid;
225
+ }
226
+
227
+ throw new Error('Either JWT or API key required');
228
+ }
229
+ }
230
+
231
+ // Use on a tool
232
+ @Tool({ name: 'multi_auth_tool' })
233
+ @UseGuards(MultiAuthGuard)
234
+ async multiAuthTool() {
235
+ // Accessible with JWT OR API key
236
+ }
237
+ ```
238
+
239
+ ### Example: Both Required
240
+
241
+ ```typescript
242
+ @Tool({ name: 'double_auth_tool' })
243
+ @UseGuards(JWTGuard, ApiKeyGuard) // Both required!
244
+ async doubleAuthTool() {
245
+ // Requires BOTH JWT token AND API key
246
+ }
247
+ ```
248
+
249
+ ## 🧪 Testing Your Tools
250
+
251
+ ### In NitroStack Studio
252
+
253
+ 1. **Set API Key** in Auth tab
254
+ 2. Navigate to **Tools** tab
255
+ 3. Test public tools (work without key)
256
+ 4. Test protected tools (work with key)
257
+ 5. Test `check_api_key_status` to verify your setup
258
+
259
+ ### Programmatically (TypeScript Client)
260
+
261
+ ```typescript
262
+ import { McpClient } from 'nitrostack';
263
+
264
+ const client = new McpClient({
265
+ transport: 'stdio',
266
+ command: 'node',
267
+ args: ['dist/index.js'],
268
+ });
269
+
270
+ await client.connect();
271
+
272
+ // Call protected tool with API key
273
+ const result = await client.callTool('get_protected_data', {
274
+ dataType: 'user',
275
+ _meta: {
276
+ apiKey: 'sk_test_public_demo_key_12345'
277
+ }
278
+ });
279
+
280
+ console.log(result);
281
+ ```
282
+
283
+ ### In Claude Desktop or Cline
284
+
285
+ Add to your MCP settings:
286
+
287
+ ```json
288
+ {
289
+ "mcpServers": {
290
+ "api-key-auth": {
291
+ "command": "node",
292
+ "args": ["/path/to/dist/index.js"],
293
+ "env": {
294
+ "API_KEY_1": "sk_test_public_demo_key_12345"
295
+ }
296
+ }
297
+ }
298
+ }
299
+ ```
300
+
301
+ ## 🔒 Production Best Practices
302
+
303
+ ### 1. Use Hashed Keys
304
+
305
+ ```typescript
306
+ apiKey: ApiKeyModule.forRoot({
307
+ keysEnvPrefix: 'API_KEY',
308
+ hashed: true, // Store keys as SHA-256 hashes
309
+ })
310
+ ```
311
+
312
+ Then hash your keys before storing:
313
+
314
+ ```typescript
315
+ import { ApiKeyModule } from 'nitrostack';
316
+
317
+ const apiKey = 'sk_prod_real_secret_key';
318
+ const hashed = ApiKeyModule.hashKey(apiKey);
319
+ console.log('Store this in .env:', hashed);
320
+ // API_KEY_1=<hash>
321
+ ```
322
+
323
+ ### 2. Use Strong Keys
324
+
325
+ ```typescript
326
+ import { ApiKeyModule } from 'nitrostack';
327
+
328
+ // Generate cryptographically secure keys
329
+ const newKey = ApiKeyModule.generateKey('sk');
330
+ console.log(newKey);
331
+ // sk_vK8mQ2xPnL...
332
+ ```
333
+
334
+ ### 3. Store Keys Securely
335
+
336
+ - ✅ Use environment variables
337
+ - ✅ Use secret management (AWS Secrets Manager, Vault, etc.)
338
+ - ❌ Never commit keys to git
339
+ - ❌ Never hardcode keys in source
340
+
341
+ ### 4. Custom Validation
342
+
343
+ ```typescript
344
+ apiKey: ApiKeyModule.forRoot({
345
+ keysEnvPrefix: 'API_KEY',
346
+ customValidation: async (key) => {
347
+ // Check against database, rate limits, expiration, etc.
348
+ const keyRecord = await db.apiKeys.findOne({ key });
349
+ return keyRecord && !keyRecord.expired;
350
+ },
351
+ })
352
+ ```
353
+
354
+ ## 📚 Available Tools
355
+
356
+ ### Public Tools (No Auth)
357
+
358
+ #### `get_public_info`
359
+ Get public information without authentication.
360
+
361
+ **Arguments:**
362
+ - `topic` (string): The topic to get information about
363
+
364
+ **Example:**
365
+ ```json
366
+ {
367
+ "topic": "weather"
368
+ }
369
+ ```
370
+
371
+ ### Protected Tools (API Key Required)
372
+
373
+ #### `get_protected_data`
374
+ Retrieve protected data (requires API key).
375
+
376
+ **Arguments:**
377
+ - `dataType` (enum): `user`, `account`, or `settings`
378
+
379
+ **Example:**
380
+ ```json
381
+ {
382
+ "dataType": "user"
383
+ }
384
+ ```
385
+
386
+ #### `perform_protected_action`
387
+ Perform a protected action (requires API key).
388
+
389
+ **Arguments:**
390
+ - `action` (enum): `create`, `update`, or `delete`
391
+ - `resourceType` (string): Type of resource
392
+ - `resourceId` (string, optional): Resource ID for update/delete
393
+
394
+ **Example:**
395
+ ```json
396
+ {
397
+ "action": "create",
398
+ "resourceType": "post"
399
+ }
400
+ ```
401
+
402
+ #### `check_api_key_status`
403
+ Verify your API key is working correctly.
404
+
405
+ **Arguments:** None
406
+
407
+ ## 🐛 Troubleshooting
408
+
409
+ ### "API key required" Error
410
+
411
+ **Solution**: Set your API key in Studio Auth tab:
412
+ 1. Go to **Auth** tab
413
+ 2. Find **API Key** section
414
+ 3. Paste: `sk_test_public_demo_key_12345`
415
+ 4. Click **Set Key**
416
+
417
+ ### "Invalid API key" Error
418
+
419
+ **Causes:**
420
+ - Wrong key format
421
+ - Key not in `.env` file
422
+ - Environment variables not loaded
423
+
424
+ **Solution:**
425
+ 1. Check `.env` has the key
426
+ 2. Restart the dev server: `npm run dev`
427
+ 3. Verify key in Studio matches `.env`
428
+
429
+ ### Public Tools Not Working
430
+
431
+ Public tools should work without authentication. If they fail:
432
+ 1. Check server logs for errors
433
+ 2. Ensure no guards are accidentally applied
434
+ 3. Test in Studio Tools tab
435
+
436
+ ## 🎓 Next Steps
437
+
438
+ 1. ✅ Explore the code in `src/`
439
+ 2. ✅ Add your own protected tools
440
+ 3. ✅ Combine with JWT auth (see `typescript-auth` template)
441
+ 4. ✅ Add custom validation logic
442
+ 5. ✅ Deploy to production with secure keys
443
+
444
+ ## 📖 Related Resources
445
+
446
+ - **NitroStack Docs**: Full documentation
447
+ - **typescript-auth Template**: JWT authentication example
448
+ - **typescript-starter Template**: Basic MCP server
449
+ - **ApiKeyModule API**: Core API key functionality
450
+
451
+ ## 💡 Tips
452
+
453
+ - 🔑 Use `sk_` prefix for secret keys (standard convention)
454
+ - 🔐 Enable hashing in production
455
+ - 🎯 Mix public and protected tools in the same server
456
+ - 🔄 Support multiple auth methods (JWT + API Key)
457
+ - 📊 Add logging to track API key usage
458
+
459
+ ## ❓ FAQ
460
+
461
+ **Q: Can I use both JWT and API key auth?**
462
+ A: Yes! See the Multi-Auth Example section above.
463
+
464
+ **Q: How do I rotate API keys?**
465
+ A: Add new keys to `.env`, deploy, then remove old keys after clients update.
466
+
467
+ **Q: Can I have per-key permissions?**
468
+ A: Yes! Use `customValidation` to check permissions in your database.
469
+
470
+ **Q: Is this production-ready?**
471
+ A: Yes, but enable `hashed: true` and use secure key storage.
472
+
473
+ **Q: How do I integrate with my existing auth system?**
474
+ A: Use `customValidation` to validate against your auth API/database.
475
+
476
+ ---
477
+
478
+ ## 🎉 You're Ready!
479
+
480
+ You now have a fully functional MCP server with API key authentication. Try it out, modify it, and build something amazing!
481
+
482
+ **Happy coding! 🚀**
483
+
@@ -0,0 +1,124 @@
1
+ {
2
+ "name": "api-key-auth-mcp-server",
3
+ "version": "1.0.0",
4
+ "lockfileVersion": 3,
5
+ "requires": true,
6
+ "packages": {
7
+ "": {
8
+ "name": "api-key-auth-mcp-server",
9
+ "version": "1.0.0",
10
+ "license": "MIT",
11
+ "dependencies": {
12
+ "nitrostack": "file:../../",
13
+ "zod": "^3.23.8"
14
+ },
15
+ "devDependencies": {
16
+ "@types/node": "^20",
17
+ "typescript": "^5"
18
+ }
19
+ },
20
+ "../..": {
21
+ "version": "1.0.0",
22
+ "license": "MIT",
23
+ "dependencies": {
24
+ "@google/generative-ai": "^0.24.1",
25
+ "@modelcontextprotocol/sdk": "^1.0.4",
26
+ "bcryptjs": "^2.4.3",
27
+ "better-sqlite3": "^11.8.1",
28
+ "chokidar": "^3.6.0",
29
+ "commander": "^12.1.0",
30
+ "cors": "^2.8.5",
31
+ "dotenv": "^17.2.3",
32
+ "express": "^4.21.2",
33
+ "fs-extra": "^11.3.2",
34
+ "http-proxy-middleware": "^3.0.3",
35
+ "inquirer": "^12.10.0",
36
+ "jose": "^6.1.0",
37
+ "jsonwebtoken": "^9.0.2",
38
+ "open": "^10.2.0",
39
+ "openai": "^6.5.0",
40
+ "ora": "^9.0.0",
41
+ "reflect-metadata": "^0.2.1",
42
+ "uuid": "^11.0.5",
43
+ "winston": "^3.17.0",
44
+ "ws": "^8.18.3",
45
+ "zod": "^3.24.1",
46
+ "zod-to-json-schema": "^3.24.6"
47
+ },
48
+ "bin": {
49
+ "nitrostack": "dist/cli/index.js"
50
+ },
51
+ "devDependencies": {
52
+ "@types/bcryptjs": "^2.4.6",
53
+ "@types/better-sqlite3": "^7.6.12",
54
+ "@types/cors": "^2.8.19",
55
+ "@types/express": "^5.0.0",
56
+ "@types/fs-extra": "^11.0.4",
57
+ "@types/jest": "^29.5.14",
58
+ "@types/jsonwebtoken": "^9.0.7",
59
+ "@types/node": "^22.10.5",
60
+ "@types/react": "^19.2.2",
61
+ "@types/uuid": "^10.0.0",
62
+ "@types/ws": "^8.18.1",
63
+ "jest": "^29.7.0",
64
+ "ts-jest": "^29.2.5",
65
+ "typescript": "^5.7.2"
66
+ },
67
+ "engines": {
68
+ "node": ">=18.0.0"
69
+ },
70
+ "peerDependencies": {
71
+ "react": "^18.0.0 || ^19.0.0"
72
+ },
73
+ "peerDependenciesMeta": {
74
+ "react": {
75
+ "optional": true
76
+ }
77
+ }
78
+ },
79
+ "node_modules/@types/node": {
80
+ "version": "20.19.23",
81
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.23.tgz",
82
+ "integrity": "sha512-yIdlVVVHXpmqRhtyovZAcSy0MiPcYWGkoO4CGe/+jpP0hmNuihm4XhHbADpK++MsiLHP5MVlv+bcgdF99kSiFQ==",
83
+ "dev": true,
84
+ "license": "MIT",
85
+ "dependencies": {
86
+ "undici-types": "~6.21.0"
87
+ }
88
+ },
89
+ "node_modules/nitrostack": {
90
+ "resolved": "../..",
91
+ "link": true
92
+ },
93
+ "node_modules/typescript": {
94
+ "version": "5.9.3",
95
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
96
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
97
+ "dev": true,
98
+ "license": "Apache-2.0",
99
+ "bin": {
100
+ "tsc": "bin/tsc",
101
+ "tsserver": "bin/tsserver"
102
+ },
103
+ "engines": {
104
+ "node": ">=14.17"
105
+ }
106
+ },
107
+ "node_modules/undici-types": {
108
+ "version": "6.21.0",
109
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
110
+ "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
111
+ "dev": true,
112
+ "license": "MIT"
113
+ },
114
+ "node_modules/zod": {
115
+ "version": "3.25.76",
116
+ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
117
+ "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
118
+ "license": "MIT",
119
+ "funding": {
120
+ "url": "https://github.com/sponsors/colinhacks"
121
+ }
122
+ }
123
+ }
124
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "api-key-auth-mcp-server",
3
+ "version": "1.0.0",
4
+ "description": "NitroStack server demonstrating API key authentication",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "scripts": {
8
+ "dev": "nitrostack dev",
9
+ "build": "nitrostack build",
10
+ "start": "nitrostack start",
11
+ "widget": "npm --prefix src/widgets"
12
+ },
13
+ "keywords": [
14
+ "mcp",
15
+ "nitrostack",
16
+ "api-key",
17
+ "authentication"
18
+ ],
19
+ "author": "",
20
+ "license": "MIT",
21
+ "dependencies": {
22
+ "nitrostack": "^1.0.0",
23
+ "zod": "^3.23.8"
24
+ },
25
+ "devDependencies": {
26
+ "@types/node": "^20",
27
+ "typescript": "^5"
28
+ }
29
+ }