apcore-mcp 0.6.1 → 0.7.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 (44) hide show
  1. package/README.md +169 -12
  2. package/dist/auth/index.d.ts +8 -0
  3. package/dist/auth/index.d.ts.map +1 -0
  4. package/dist/auth/index.js +6 -0
  5. package/dist/auth/index.js.map +1 -0
  6. package/dist/auth/jwt.d.ts +59 -0
  7. package/dist/auth/jwt.d.ts.map +1 -0
  8. package/dist/auth/jwt.js +95 -0
  9. package/dist/auth/jwt.js.map +1 -0
  10. package/dist/auth/storage.d.ts +18 -0
  11. package/dist/auth/storage.d.ts.map +1 -0
  12. package/dist/auth/storage.js +19 -0
  13. package/dist/auth/storage.js.map +1 -0
  14. package/dist/auth/types.d.ts +21 -0
  15. package/dist/auth/types.d.ts.map +1 -0
  16. package/dist/auth/types.js +8 -0
  17. package/dist/auth/types.js.map +1 -0
  18. package/dist/cli.d.ts.map +1 -1
  19. package/dist/cli.js +37 -2
  20. package/dist/cli.js.map +1 -1
  21. package/dist/explorer/handler.d.ts +10 -1
  22. package/dist/explorer/handler.d.ts.map +1 -1
  23. package/dist/explorer/handler.js +47 -21
  24. package/dist/explorer/handler.js.map +1 -1
  25. package/dist/explorer/html.d.ts +2 -2
  26. package/dist/explorer/html.d.ts.map +1 -1
  27. package/dist/explorer/html.js +126 -47
  28. package/dist/explorer/html.js.map +1 -1
  29. package/dist/index.d.ts +9 -0
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +11 -1
  32. package/dist/index.js.map +1 -1
  33. package/dist/server/context.d.ts +5 -2
  34. package/dist/server/context.d.ts.map +1 -1
  35. package/dist/server/context.js +7 -5
  36. package/dist/server/context.js.map +1 -1
  37. package/dist/server/router.d.ts.map +1 -1
  38. package/dist/server/router.js +4 -2
  39. package/dist/server/router.js.map +1 -1
  40. package/dist/server/transport.d.ts +34 -1
  41. package/dist/server/transport.d.ts.map +1 -1
  42. package/dist/server/transport.js +149 -60
  43. package/dist/server/transport.js.map +1 -1
  44. package/package.json +4 -2
package/README.md CHANGED
@@ -16,6 +16,7 @@ Converts apcore module registries into [Model Context Protocol (MCP)](https://mo
16
16
  - **Annotation Mapping** — Map module annotations to MCP hints and OpenAI description suffixes
17
17
  - **Error Mapping** — Sanitize internal errors for safe client-facing responses
18
18
  - **Dynamic Registration** — Listen for registry changes and update tools at runtime
19
+ - **Tool Explorer** — Browser-based UI for browsing schemas and testing tools interactively
19
20
  - **CLI** — Launch an MCP server from the command line
20
21
 
21
22
  ## Requirements
@@ -78,6 +79,73 @@ npx apcore-mcp --extensions-dir ./extensions --transport sse --port 8000
78
79
  | `--name` | `apcore-mcp` | MCP server name |
79
80
  | `--version` | package version | MCP server version |
80
81
  | `--log-level` | `INFO` | `DEBUG`, `INFO`, `WARNING`, `ERROR` |
82
+ | `--explorer` | off | Enable the browser-based Tool Explorer UI (HTTP only) |
83
+ | `--explorer-prefix` | `/explorer` | URL prefix for the explorer UI |
84
+ | `--allow-execute` | off | Allow tool execution from the explorer UI |
85
+ | `--jwt-secret` | — | JWT secret key for Bearer token authentication |
86
+ | `--jwt-algorithm` | `HS256` | JWT algorithm |
87
+ | `--jwt-audience` | — | Expected JWT audience claim |
88
+ | `--jwt-issuer` | — | Expected JWT issuer claim |
89
+ | `--jwt-require-auth` | `true` | Require auth (use `--no-jwt-require-auth` for permissive mode) |
90
+ | `--exempt-paths` | `/health,/metrics` | Comma-separated paths exempt from auth |
91
+
92
+ ## MCP Client Configuration
93
+
94
+ ### Claude Desktop
95
+
96
+ Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
97
+
98
+ ```json
99
+ {
100
+ "mcpServers": {
101
+ "apcore": {
102
+ "command": "npx",
103
+ "args": ["apcore-mcp", "--extensions-dir", "/path/to/your/extensions"]
104
+ }
105
+ }
106
+ }
107
+ ```
108
+
109
+ ### Claude Code
110
+
111
+ Add to `.mcp.json` in your project root:
112
+
113
+ ```json
114
+ {
115
+ "mcpServers": {
116
+ "apcore": {
117
+ "command": "npx",
118
+ "args": ["apcore-mcp", "--extensions-dir", "./extensions"]
119
+ }
120
+ }
121
+ }
122
+ ```
123
+
124
+ ### Cursor
125
+
126
+ Add to `.cursor/mcp.json` in your project root:
127
+
128
+ ```json
129
+ {
130
+ "mcpServers": {
131
+ "apcore": {
132
+ "command": "npx",
133
+ "args": ["apcore-mcp", "--extensions-dir", "./extensions"]
134
+ }
135
+ }
136
+ }
137
+ ```
138
+
139
+ ### Remote HTTP access
140
+
141
+ ```bash
142
+ npx apcore-mcp --extensions-dir ./extensions \
143
+ --transport streamable-http \
144
+ --host 0.0.0.0 \
145
+ --port 9000
146
+ ```
147
+
148
+ Connect any MCP client to `http://your-host:9000/mcp`.
81
149
 
82
150
  ## API Reference
83
151
 
@@ -94,10 +162,101 @@ function serve(
94
162
  port?: number;
95
163
  name?: string;
96
164
  version?: string;
165
+ explorer?: boolean;
166
+ explorerPrefix?: string;
167
+ allowExecute?: boolean;
168
+ authenticator?: Authenticator;
169
+ exemptPaths?: string[];
97
170
  }
98
171
  ): Promise<void>;
99
172
  ```
100
173
 
174
+ ### Tool Explorer
175
+
176
+ When `explorer: true` is passed to `serve()`, a browser-based Tool Explorer UI is mounted on HTTP transports. It provides an interactive page for browsing tool schemas and testing tool execution.
177
+
178
+ ```typescript
179
+ await serve(registry, {
180
+ transport: "streamable-http",
181
+ explorer: true,
182
+ allowExecute: true,
183
+ });
184
+ // Open http://127.0.0.1:8000/explorer/ in a browser
185
+ ```
186
+
187
+ **Endpoints:**
188
+
189
+ | Endpoint | Description |
190
+ |----------|-------------|
191
+ | `GET /explorer/` | Interactive HTML page (self-contained, no external dependencies) |
192
+ | `GET /explorer/tools` | JSON array of all tools with name, description, annotations |
193
+ | `GET /explorer/tools/<name>` | Full tool detail with inputSchema |
194
+ | `POST /explorer/tools/<name>/call` | Execute a tool (requires `allowExecute: true`) |
195
+
196
+ - **HTTP transports only** (`streamable-http`, `sse`). Silently ignored for `stdio`.
197
+ - **Execution disabled by default** — set `allowExecute: true` to enable Try-it.
198
+ - **Custom prefix** — use `explorerPrefix: "/browse"` to mount at a different path.
199
+ - **Authorization UI** — Swagger-UI-style Authorization input field. Paste a Bearer token to authenticate tool execution requests. Generated cURL commands automatically include the Authorization header.
200
+
201
+ ### JWT Authentication
202
+
203
+ apcore-mcp supports JWT Bearer token authentication for HTTP-based transports.
204
+
205
+ #### Programmatic Usage
206
+
207
+ ```typescript
208
+ import { serve, JWTAuthenticator } from "apcore-mcp";
209
+
210
+ const authenticator = new JWTAuthenticator({
211
+ secret: "your-secret-key",
212
+ algorithms: ["HS256"],
213
+ audience: "my-app",
214
+ issuer: "auth-service",
215
+ // Map custom claims to Identity fields
216
+ claimMapping: {
217
+ id: "sub",
218
+ type: "type",
219
+ roles: "roles",
220
+ attrs: ["email", "org"], // Extra claims → Identity.attrs
221
+ },
222
+ // Claims that must be present in the token (default: ["sub"])
223
+ requireClaims: ["sub", "email"],
224
+ // Set to false for permissive mode (allow unauthenticated requests)
225
+ requireAuth: true,
226
+ });
227
+
228
+ await serve(executor, {
229
+ transport: "streamable-http",
230
+ authenticator,
231
+ // Custom exempt paths (default: ["/health", "/metrics"])
232
+ exemptPaths: ["/health", "/metrics", "/status"],
233
+ });
234
+ ```
235
+
236
+ #### CLI Flags
237
+
238
+ | Flag | Default | Description |
239
+ |------|---------|-------------|
240
+ | `--jwt-secret` | — | JWT secret key for Bearer token authentication |
241
+ | `--jwt-algorithm` | `HS256` | JWT algorithm |
242
+ | `--jwt-audience` | — | Expected audience claim |
243
+ | `--jwt-issuer` | — | Expected issuer claim |
244
+ | `--jwt-require-auth` | `true` | Require auth. Use `--no-jwt-require-auth` for permissive mode |
245
+ | `--exempt-paths` | `/health,/metrics` | Comma-separated paths exempt from auth |
246
+
247
+ #### curl Examples
248
+
249
+ ```bash
250
+ # Authenticated request
251
+ curl -X POST http://localhost:8000/mcp \
252
+ -H "Content-Type: application/json" \
253
+ -H "Authorization: Bearer <your-jwt-token>" \
254
+ -d '{"jsonrpc":"2.0","method":"tools/list","id":1}'
255
+
256
+ # Health check (always exempt)
257
+ curl http://localhost:8000/health
258
+ ```
259
+
101
260
  ### `toOpenaiTools(registryOrExecutor, options?)`
102
261
 
103
262
  Export apcore modules as OpenAI-compatible tool definitions.
@@ -128,16 +287,25 @@ src/
128
287
  ├── index.ts # Public API: serve(), toOpenaiTools()
129
288
  ├── cli.ts # CLI entry point
130
289
  ├── types.ts # TypeScript interfaces
290
+ ├── helpers.ts # reportProgress() / elicit() helpers
131
291
  ├── adapters/
132
292
  │ ├── schema.ts # JSON Schema $ref inlining
133
293
  │ ├── annotations.ts # Module annotations -> MCP hints
134
294
  │ ├── errors.ts # Error sanitization
135
295
  │ └── idNormalizer.ts # Dot-notation <-> dash-notation
296
+ ├── auth/
297
+ │ ├── jwt.ts # JWT Bearer token authenticator
298
+ │ ├── storage.ts # AsyncLocalStorage identity propagation
299
+ │ └── types.ts # Authenticator / Identity interfaces
136
300
  ├── converters/
137
301
  │ └── openai.ts # OpenAI tool definition converter
302
+ ├── explorer/
303
+ │ ├── handler.ts # Explorer HTTP route handler
304
+ │ └── html.ts # Self-contained HTML/CSS/JS page
138
305
  └── server/
139
306
  ├── factory.ts # MCP Server creation & handler registration
140
307
  ├── router.ts # Tool call execution routing
308
+ ├── context.ts # BridgeContext for executor call chains
141
309
  ├── transport.ts # Transport lifecycle (stdio/HTTP/SSE)
142
310
  └── listener.ts # Dynamic registry event listener
143
311
  ```
@@ -176,18 +344,7 @@ npm run dev
176
344
 
177
345
  ## Testing
178
346
 
179
- 100 tests across 10 test suites with 96%+ line coverage:
180
-
181
- | Module | Coverage |
182
- |---|---|
183
- | annotations.ts | 100% |
184
- | idNormalizer.ts | 100% |
185
- | factory.ts | 100% |
186
- | router.ts | 100% |
187
- | errors.ts | 98.8% |
188
- | schema.ts | 97.0% |
189
- | openai.ts | 91.7% |
190
- | listener.ts | 89.7% |
347
+ 284 tests across 22 test suites.
191
348
 
192
349
  ## License
193
350
 
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Auth module barrel exports.
3
+ */
4
+ export type { Authenticator, Identity } from "./types.js";
5
+ export { JWTAuthenticator } from "./jwt.js";
6
+ export type { ClaimMapping, JWTAuthenticatorOptions } from "./jwt.js";
7
+ export { identityStorage, getCurrentIdentity } from "./storage.js";
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,YAAY,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Auth module barrel exports.
3
+ */
4
+ export { JWTAuthenticator } from "./jwt.js";
5
+ export { identityStorage, getCurrentIdentity } from "./storage.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAE5C,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * JWT Authenticator — verifies Bearer tokens and maps claims to Identity.
3
+ *
4
+ * Mirrors the Python `JWTAuthenticator` from apcore-mcp-python.
5
+ */
6
+ import type { IncomingMessage } from "node:http";
7
+ import jwt from "jsonwebtoken";
8
+ import { type Identity } from "apcore-js";
9
+ import type { Authenticator } from "./types.js";
10
+ /** Mapping from JWT claims to Identity fields. */
11
+ export interface ClaimMapping {
12
+ /** JWT claim for Identity.id. Default: "sub" */
13
+ id?: string;
14
+ /** JWT claim for Identity.type. Default: "type" */
15
+ type?: string;
16
+ /** JWT claim for Identity.roles. Default: "roles" */
17
+ roles?: string;
18
+ /** Extra claims to copy into Identity.attrs. */
19
+ attrs?: string[];
20
+ }
21
+ /** Options for constructing a JWTAuthenticator. */
22
+ export interface JWTAuthenticatorOptions {
23
+ /** Secret key (symmetric) or public key (asymmetric) for token verification. */
24
+ secret: string;
25
+ /** Allowed algorithms. Default: ["HS256"] */
26
+ algorithms?: jwt.Algorithm[];
27
+ /** Expected audience claim. */
28
+ audience?: string;
29
+ /** Expected issuer claim. */
30
+ issuer?: string;
31
+ /** Custom claim-to-Identity field mapping. */
32
+ claimMapping?: ClaimMapping;
33
+ /** Claims that must be present in the token. Default: ["sub"] */
34
+ requireClaims?: string[];
35
+ /** If true (default), unauthenticated requests are rejected. If false, they proceed without identity. */
36
+ requireAuth?: boolean;
37
+ }
38
+ /**
39
+ * Authenticator that verifies JWT Bearer tokens from the Authorization header.
40
+ *
41
+ * Returns an Identity on success, or `null` if:
42
+ * - No Authorization header is present
43
+ * - The header is not a valid "Bearer <token>" format
44
+ * - The token fails verification (expired, wrong signature, etc.)
45
+ */
46
+ export declare class JWTAuthenticator implements Authenticator {
47
+ private readonly _secret;
48
+ private readonly _algorithms;
49
+ private readonly _audience?;
50
+ private readonly _issuer?;
51
+ private readonly _claimMapping;
52
+ private readonly _requireClaims;
53
+ private readonly _requireAuth;
54
+ constructor(options: JWTAuthenticatorOptions);
55
+ /** Whether unauthenticated requests should be rejected. */
56
+ get requireAuth(): boolean;
57
+ authenticate(req: IncomingMessage): Promise<Identity | null>;
58
+ }
59
+ //# sourceMappingURL=jwt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../src/auth/jwt.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,GAAG,MAAM,cAAc,CAAC;AAC/B,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,kDAAkD;AAClD,MAAM,WAAW,YAAY;IAC3B,gDAAgD;IAChD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,mDAAmD;IACnD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qDAAqD;IACrD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gDAAgD;IAChD,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,mDAAmD;AACnD,MAAM,WAAW,uBAAuB;IACtC,gFAAgF;IAChF,MAAM,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,UAAU,CAAC,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC;IAC7B,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8CAA8C;IAC9C,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,iEAAiE;IACjE,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,yGAAyG;IACzG,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,qBAAa,gBAAiB,YAAW,aAAa;IACpD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAkB;IAC9C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA+D;IAC7F,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAW;IAC1C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAU;gBAE3B,OAAO,EAAE,uBAAuB;IAe5C,2DAA2D;IAC3D,IAAI,WAAW,IAAI,OAAO,CAEzB;IAEK,YAAY,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;CAsDnE"}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * JWT Authenticator — verifies Bearer tokens and maps claims to Identity.
3
+ *
4
+ * Mirrors the Python `JWTAuthenticator` from apcore-mcp-python.
5
+ */
6
+ import jwt from "jsonwebtoken";
7
+ import { createIdentity } from "apcore-js";
8
+ /**
9
+ * Authenticator that verifies JWT Bearer tokens from the Authorization header.
10
+ *
11
+ * Returns an Identity on success, or `null` if:
12
+ * - No Authorization header is present
13
+ * - The header is not a valid "Bearer <token>" format
14
+ * - The token fails verification (expired, wrong signature, etc.)
15
+ */
16
+ export class JWTAuthenticator {
17
+ _secret;
18
+ _algorithms;
19
+ _audience;
20
+ _issuer;
21
+ _claimMapping;
22
+ _requireClaims;
23
+ _requireAuth;
24
+ constructor(options) {
25
+ this._secret = options.secret;
26
+ this._algorithms = options.algorithms ?? ["HS256"];
27
+ this._audience = options.audience;
28
+ this._issuer = options.issuer;
29
+ this._claimMapping = {
30
+ id: options.claimMapping?.id ?? "sub",
31
+ type: options.claimMapping?.type ?? "type",
32
+ roles: options.claimMapping?.roles ?? "roles",
33
+ attrs: options.claimMapping?.attrs,
34
+ };
35
+ this._requireClaims = options.requireClaims ?? ["sub"];
36
+ this._requireAuth = options.requireAuth ?? true;
37
+ }
38
+ /** Whether unauthenticated requests should be rejected. */
39
+ get requireAuth() {
40
+ return this._requireAuth;
41
+ }
42
+ async authenticate(req) {
43
+ const authHeader = req.headers.authorization;
44
+ if (!authHeader)
45
+ return null;
46
+ // Must be "Bearer <token>"
47
+ const parts = authHeader.split(" ");
48
+ if (parts.length !== 2 || parts[0].toLowerCase() !== "bearer")
49
+ return null;
50
+ const token = parts[1];
51
+ if (!token)
52
+ return null;
53
+ try {
54
+ const verifyOptions = {
55
+ algorithms: this._algorithms,
56
+ };
57
+ if (this._audience)
58
+ verifyOptions.audience = this._audience;
59
+ if (this._issuer)
60
+ verifyOptions.issuer = this._issuer;
61
+ const payload = jwt.verify(token, this._secret, verifyOptions);
62
+ // payload can be string (rare) or JwtPayload object
63
+ if (typeof payload === "string")
64
+ return null;
65
+ const claims = payload;
66
+ // Check required claims are present
67
+ for (const claim of this._requireClaims) {
68
+ if (!(claim in claims))
69
+ return null;
70
+ }
71
+ const rawId = claims[this._claimMapping.id];
72
+ if (rawId === undefined || rawId === null)
73
+ return null;
74
+ const id = String(rawId);
75
+ const type = String(claims[this._claimMapping.type] ?? "user");
76
+ const rawRoles = claims[this._claimMapping.roles];
77
+ const roles = Array.isArray(rawRoles) ? rawRoles.map(String) : [];
78
+ // Extract attrs from payload
79
+ const attrs = {};
80
+ if (this._claimMapping.attrs) {
81
+ for (const key of this._claimMapping.attrs) {
82
+ if (key in claims) {
83
+ attrs[key] = claims[key];
84
+ }
85
+ }
86
+ }
87
+ return createIdentity(id, type, roles, attrs);
88
+ }
89
+ catch {
90
+ // Verification failed (expired, invalid signature, etc.)
91
+ return null;
92
+ }
93
+ }
94
+ }
95
+ //# sourceMappingURL=jwt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt.js","sourceRoot":"","sources":["../../src/auth/jwt.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,GAAG,MAAM,cAAc,CAAC;AAC/B,OAAO,EAAE,cAAc,EAAiB,MAAM,WAAW,CAAC;AAiC1D;;;;;;;GAOG;AACH,MAAM,OAAO,gBAAgB;IACV,OAAO,CAAS;IAChB,WAAW,CAAkB;IAC7B,SAAS,CAAU;IACnB,OAAO,CAAU;IACjB,aAAa,CAA+D;IAC5E,cAAc,CAAW;IACzB,YAAY,CAAU;IAEvC,YAAY,OAAgC;QAC1C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC;QAC9B,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,UAAU,IAAI,CAAC,OAAO,CAAC,CAAC;QACnD,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAC;QAClC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC;QAC9B,IAAI,CAAC,aAAa,GAAG;YACnB,EAAE,EAAE,OAAO,CAAC,YAAY,EAAE,EAAE,IAAI,KAAK;YACrC,IAAI,EAAE,OAAO,CAAC,YAAY,EAAE,IAAI,IAAI,MAAM;YAC1C,KAAK,EAAE,OAAO,CAAC,YAAY,EAAE,KAAK,IAAI,OAAO;YAC7C,KAAK,EAAE,OAAO,CAAC,YAAY,EAAE,KAAK;SACnC,CAAC;QACF,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,aAAa,IAAI,CAAC,KAAK,CAAC,CAAC;QACvD,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,WAAW,IAAI,IAAI,CAAC;IAClD,CAAC;IAED,2DAA2D;IAC3D,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,GAAoB;QACrC,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC;QAC7C,IAAI,CAAC,UAAU;YAAE,OAAO,IAAI,CAAC;QAE7B,2BAA2B;QAC3B,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QAE3E,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACvB,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QAExB,IAAI,CAAC;YACH,MAAM,aAAa,GAAsB;gBACvC,UAAU,EAAE,IAAI,CAAC,WAAW;aAC7B,CAAC;YACF,IAAI,IAAI,CAAC,SAAS;gBAAE,aAAa,CAAC,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC;YAC5D,IAAI,IAAI,CAAC,OAAO;gBAAE,aAAa,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC;YAEtD,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;YAE/D,oDAAoD;YACpD,IAAI,OAAO,OAAO,KAAK,QAAQ;gBAAE,OAAO,IAAI,CAAC;YAE7C,MAAM,MAAM,GAAG,OAAkC,CAAC;YAElD,oCAAoC;YACpC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;gBACxC,IAAI,CAAC,CAAC,KAAK,IAAI,MAAM,CAAC;oBAAE,OAAO,IAAI,CAAC;YACtC,CAAC;YAED,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;YAC5C,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;gBAAE,OAAO,IAAI,CAAC;YACvD,MAAM,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;YACzB,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,CAAC;YAE/D,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YAClD,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAElE,6BAA6B;YAC7B,MAAM,KAAK,GAA4B,EAAE,CAAC;YAC1C,IAAI,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC;gBAC7B,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC;oBAC3C,IAAI,GAAG,IAAI,MAAM,EAAE,CAAC;wBAClB,KAAK,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;oBAC3B,CAAC;gBACH,CAAC;YACH,CAAC;YAED,OAAO,cAAc,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;QAChD,CAAC;QAAC,MAAM,CAAC;YACP,yDAAyD;YACzD,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Identity propagation via AsyncLocalStorage.
3
+ *
4
+ * Replaces Python's ContextVar pattern for propagating the authenticated
5
+ * identity through the async call chain without explicit parameter passing.
6
+ */
7
+ import { AsyncLocalStorage } from "node:async_hooks";
8
+ import type { Identity } from "apcore-js";
9
+ /** AsyncLocalStorage instance that carries the current Identity through async scopes. */
10
+ export declare const identityStorage: AsyncLocalStorage<Identity | null>;
11
+ /**
12
+ * Get the current Identity from the async context.
13
+ *
14
+ * Returns `null` if called outside an `identityStorage.run()` scope
15
+ * or if the scope was entered with a `null` identity.
16
+ */
17
+ export declare function getCurrentIdentity(): Identity | null;
18
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/auth/storage.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE1C,yFAAyF;AACzF,eAAO,MAAM,eAAe,oCAA2C,CAAC;AAExE;;;;;GAKG;AACH,wBAAgB,kBAAkB,IAAI,QAAQ,GAAG,IAAI,CAEpD"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Identity propagation via AsyncLocalStorage.
3
+ *
4
+ * Replaces Python's ContextVar pattern for propagating the authenticated
5
+ * identity through the async call chain without explicit parameter passing.
6
+ */
7
+ import { AsyncLocalStorage } from "node:async_hooks";
8
+ /** AsyncLocalStorage instance that carries the current Identity through async scopes. */
9
+ export const identityStorage = new AsyncLocalStorage();
10
+ /**
11
+ * Get the current Identity from the async context.
12
+ *
13
+ * Returns `null` if called outside an `identityStorage.run()` scope
14
+ * or if the scope was entered with a `null` identity.
15
+ */
16
+ export function getCurrentIdentity() {
17
+ return identityStorage.getStore() ?? null;
18
+ }
19
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/auth/storage.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAGrD,yFAAyF;AACzF,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,iBAAiB,EAAmB,CAAC;AAExE;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB;IAChC,OAAO,eAAe,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC;AAC5C,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Authentication interfaces for apcore-mcp.
3
+ *
4
+ * Re-exports the Identity type from apcore-js and defines the
5
+ * Authenticator interface that transport-level auth implementations must satisfy.
6
+ */
7
+ import type { IncomingMessage } from "node:http";
8
+ import type { Identity } from "apcore-js";
9
+ export type { Identity };
10
+ /**
11
+ * Authenticator interface — implemented by auth strategies (e.g. JWT).
12
+ *
13
+ * `authenticate()` inspects incoming HTTP headers and returns an Identity
14
+ * for authenticated requests, or `null` for unauthenticated/invalid requests.
15
+ */
16
+ export interface Authenticator {
17
+ authenticate(req: IncomingMessage): Promise<Identity | null>;
18
+ /** Whether unauthenticated requests should be rejected. Default true. */
19
+ readonly requireAuth?: boolean;
20
+ }
21
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAG1C,YAAY,EAAE,QAAQ,EAAE,CAAC;AAEzB;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,YAAY,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IAC7D,yEAAyE;IACzE,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;CAChC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Authentication interfaces for apcore-mcp.
3
+ *
4
+ * Re-exports the Identity type from apcore-js and defines the
5
+ * Authenticator interface that transport-level auth implementations must satisfy.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;;;;;;GAOG;AAoCH,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAkH1C"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;;;;;;GAOG;AA4CH,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAgJ1C"}
package/dist/cli.js CHANGED
@@ -10,7 +10,7 @@
10
10
  import { existsSync, statSync } from "node:fs";
11
11
  import { resolve } from "node:path";
12
12
  import { parseArgs } from "node:util";
13
- import { serve, VERSION } from "./index.js";
13
+ import { serve, VERSION, JWTAuthenticator } from "./index.js";
14
14
  function printUsage() {
15
15
  console.log(`
16
16
  apcore-mcp v${VERSION} - Automatic MCP Server for apcore modules
@@ -31,6 +31,13 @@ Options:
31
31
  --explorer Enable the browser-based Tool Explorer UI (HTTP only)
32
32
  --explorer-prefix <path> URL prefix for the explorer UI (default: /explorer)
33
33
  --allow-execute Allow tool execution from the explorer UI
34
+ --jwt-secret <string> JWT secret key for Bearer token authentication
35
+ --jwt-algorithm <alg> JWT algorithm (default: HS256)
36
+ --jwt-audience <string> Expected JWT audience claim
37
+ --jwt-issuer <string> Expected JWT issuer claim
38
+ --jwt-require-auth Require auth (default: true)
39
+ --jwt-permissive Permissive mode: allow unauthenticated requests (overrides --jwt-require-auth)
40
+ --exempt-paths <paths> Comma-separated paths exempt from auth (default: /health,/metrics)
34
41
  --help Show this help message
35
42
  `);
36
43
  }
@@ -53,6 +60,13 @@ export async function main() {
53
60
  explorer: { type: "boolean", default: false },
54
61
  "explorer-prefix": { type: "string", default: "/explorer" },
55
62
  "allow-execute": { type: "boolean", default: false },
63
+ "jwt-secret": { type: "string" },
64
+ "jwt-algorithm": { type: "string" },
65
+ "jwt-audience": { type: "string" },
66
+ "jwt-issuer": { type: "string" },
67
+ "jwt-require-auth": { type: "boolean", default: true },
68
+ "jwt-permissive": { type: "boolean", default: false },
69
+ "exempt-paths": { type: "string" },
56
70
  help: { type: "boolean", default: false },
57
71
  },
58
72
  strict: true,
@@ -116,10 +130,29 @@ export async function main() {
116
130
  }
117
131
  // Validate log-level
118
132
  const logLevel = values["log-level"];
119
- const validLogLevels = ["DEBUG", "INFO", "WARNING", "ERROR"];
133
+ const validLogLevels = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"];
120
134
  if (logLevel && !validLogLevels.includes(logLevel)) {
121
135
  fail(`--log-level must be one of: ${validLogLevels.join(", ")}. Got '${logLevel}'.`);
122
136
  }
137
+ // Build JWT authenticator if --jwt-secret is provided
138
+ const jwtSecret = values["jwt-secret"];
139
+ const jwtRequireAuth = values["jwt-permissive"] ? false : values["jwt-require-auth"];
140
+ const authenticator = jwtSecret
141
+ ? new JWTAuthenticator({
142
+ secret: jwtSecret,
143
+ algorithms: values["jwt-algorithm"]
144
+ ? [values["jwt-algorithm"]]
145
+ : undefined,
146
+ audience: values["jwt-audience"],
147
+ issuer: values["jwt-issuer"],
148
+ requireAuth: jwtRequireAuth,
149
+ })
150
+ : undefined;
151
+ // Parse exempt paths
152
+ const exemptPathsRaw = values["exempt-paths"];
153
+ const exemptPaths = exemptPathsRaw
154
+ ? exemptPathsRaw.split(",").map((p) => p.trim())
155
+ : undefined;
123
156
  // Launch the MCP server
124
157
  try {
125
158
  await serve(registry, {
@@ -132,6 +165,8 @@ export async function main() {
132
165
  explorer: values.explorer,
133
166
  explorerPrefix: values["explorer-prefix"],
134
167
  allowExecute: values["allow-execute"],
168
+ authenticator,
169
+ exemptPaths,
135
170
  });
136
171
  }
137
172
  catch (error) {
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -13,12 +13,16 @@
13
13
  import type { IncomingMessage, ServerResponse } from "node:http";
14
14
  import type { Tool } from "@modelcontextprotocol/sdk/types.js";
15
15
  import type { ExecutionRouter } from "../server/router.js";
16
+ import type { Authenticator } from "../auth/types.js";
17
+ import type { Identity } from "apcore-js";
16
18
  /** Options for creating an ExplorerHandler. */
17
19
  export interface ExplorerHandlerOptions {
18
20
  /** Whether to allow tool execution from the explorer UI. Default: false */
19
21
  allowExecute?: boolean;
20
22
  /** URL prefix for the explorer. Default: "/explorer" */
21
23
  prefix?: string;
24
+ /** Optional authenticator for explorer POST calls. */
25
+ authenticator?: Authenticator;
22
26
  }
23
27
  export declare class ExplorerHandler {
24
28
  private readonly _toolsByName;
@@ -26,15 +30,20 @@ export declare class ExplorerHandler {
26
30
  private readonly _router;
27
31
  private readonly _allowExecute;
28
32
  private readonly _prefix;
33
+ private readonly _authenticator?;
29
34
  constructor(tools: Tool[], router: ExecutionRouter, options?: ExplorerHandlerOptions);
30
35
  /** The URL prefix this handler is mounted at. */
31
36
  get prefix(): string;
32
37
  /**
33
38
  * Attempt to handle an HTTP request.
34
39
  *
40
+ * @param req - The incoming HTTP request
41
+ * @param res - The server response
42
+ * @param url - The parsed URL
43
+ * @param identity - Pre-authenticated identity from transport layer (if any)
35
44
  * @returns true if the request was handled, false if it should be passed through
36
45
  */
37
- handleRequest(req: IncomingMessage, res: ServerResponse, url: URL): Promise<boolean>;
46
+ handleRequest(req: IncomingMessage, res: ServerResponse, url: URL, identity?: Identity | null): Promise<boolean>;
38
47
  /**
39
48
  * Build a summary dict for a tool (used in the list endpoint).
40
49
  */
@@ -1 +1 @@
1
- {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/explorer/handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAI3D,+CAA+C;AAC/C,MAAM,WAAW,sBAAsB;IACrC,2EAA2E;IAC3E,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAKD,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAoB;IACjD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkB;IAC1C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAU;IACxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAG/B,KAAK,EAAE,IAAI,EAAE,EACb,MAAM,EAAE,eAAe,EACvB,OAAO,CAAC,EAAE,sBAAsB;IASlC,iDAAiD;IACjD,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED;;;;OAIG;IACG,aAAa,CACjB,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,GAAG,EAAE,GAAG,GACP,OAAO,CAAC,OAAO,CAAC;IA6CnB;;OAEG;IACH,OAAO,CAAC,YAAY;IAWpB;;OAEG;IACH,OAAO,CAAC,WAAW;IAYnB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAWzB;;OAEG;YACW,eAAe;CAyD9B"}
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/explorer/handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAG3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAG1C,+CAA+C;AAC/C,MAAM,WAAW,sBAAsB;IACrC,2EAA2E;IAC3E,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAKD,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAoB;IACjD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkB;IAC1C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAU;IACxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAgB;gBAG9C,KAAK,EAAE,IAAI,EAAE,EACb,MAAM,EAAE,eAAe,EACvB,OAAO,CAAC,EAAE,sBAAsB;IAUlC,iDAAiD;IACjD,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED;;;;;;;;OAQG;IACG,aAAa,CACjB,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,GAAG,EAAE,GAAG,EACR,QAAQ,CAAC,EAAE,QAAQ,GAAG,IAAI,GACzB,OAAO,CAAC,OAAO,CAAC;IAwDnB;;OAEG;IACH,OAAO,CAAC,YAAY;IAWpB;;OAEG;IACH,OAAO,CAAC,WAAW;IAYnB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAWzB;;OAEG;YACW,eAAe;CAmE9B"}