@casys/mcp-server 0.2.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 +417 -0
- package/mod.ts +161 -0
- package/package.json +32 -0
- package/src/auth/config.ts +229 -0
- package/src/auth/jwt-provider.ts +175 -0
- package/src/auth/middleware.ts +170 -0
- package/src/auth/mod.ts +44 -0
- package/src/auth/presets.ts +129 -0
- package/src/auth/provider.ts +47 -0
- package/src/auth/scope-middleware.ts +59 -0
- package/src/auth/types.ts +69 -0
- package/src/concurrency/rate-limiter.ts +190 -0
- package/src/concurrency/request-queue.ts +140 -0
- package/src/concurrent-server.ts +1899 -0
- package/src/middleware/backpressure.ts +36 -0
- package/src/middleware/mod.ts +21 -0
- package/src/middleware/rate-limit.ts +45 -0
- package/src/middleware/runner.ts +63 -0
- package/src/middleware/types.ts +60 -0
- package/src/middleware/validation.ts +28 -0
- package/src/observability/metrics.ts +378 -0
- package/src/observability/mod.ts +20 -0
- package/src/observability/otel.ts +109 -0
- package/src/runtime/runtime.ts +220 -0
- package/src/runtime/types.ts +90 -0
- package/src/sampling/sampling-bridge.ts +191 -0
- package/src/security/channel-hmac.ts +140 -0
- package/src/security/csp.ts +87 -0
- package/src/security/message-signer.ts +223 -0
- package/src/types.ts +478 -0
- package/src/validation/schema-validator.ts +238 -0
package/README.md
ADDED
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
# @casys/mcp-server
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@casys/mcp-server)
|
|
4
|
+
[](https://jsr.io/@casys/mcp-server)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
**The "Hono for MCP"** — a production-grade framework for building Model Context Protocol servers in TypeScript.
|
|
8
|
+
|
|
9
|
+
Composable middleware, OAuth2 auth, dual transport, observability, and everything you need to ship reliable MCP servers. Built on the official [@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/sdk).
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
rate-limit → auth → custom middleware → scope-check → validation → backpressure → handler
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Why @casys/mcp-server?
|
|
18
|
+
|
|
19
|
+
The official SDK gives you the protocol. This framework gives you the production stack.
|
|
20
|
+
|
|
21
|
+
| | Official SDK | @casys/mcp-server |
|
|
22
|
+
| ----------------------- | :----------: | :----------------------------: |
|
|
23
|
+
| MCP protocol compliance | Yes | Yes |
|
|
24
|
+
| Concurrency control | -- | 3 backpressure strategies |
|
|
25
|
+
| Middleware pipeline | -- | Composable onion model |
|
|
26
|
+
| OAuth2 / JWT auth | -- | Built-in + 4 OIDC presets |
|
|
27
|
+
| Rate limiting | -- | Sliding window, per-client |
|
|
28
|
+
| Schema validation | -- | JSON Schema (ajv) |
|
|
29
|
+
| Streamable HTTP + SSE | Manual | Built-in session management |
|
|
30
|
+
| OpenTelemetry tracing | -- | Automatic spans per tool call |
|
|
31
|
+
| Prometheus metrics | -- | `/metrics` endpoint |
|
|
32
|
+
| MCP Apps (UI resources) | Manual | `registerResource()` + `ui://` |
|
|
33
|
+
| Sampling bridge | -- | Bidirectional LLM delegation |
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Install
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# npm
|
|
41
|
+
npm install @casys/mcp-server
|
|
42
|
+
|
|
43
|
+
# Deno
|
|
44
|
+
deno add jsr:@casys/mcp-server
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Quick Start
|
|
50
|
+
|
|
51
|
+
### STDIO Server (5 lines)
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import { ConcurrentMCPServer } from "@casys/mcp-server";
|
|
55
|
+
|
|
56
|
+
const server = new ConcurrentMCPServer({ name: "my-server", version: "1.0.0" });
|
|
57
|
+
|
|
58
|
+
server.registerTool(
|
|
59
|
+
{
|
|
60
|
+
name: "greet",
|
|
61
|
+
description: "Greet a user",
|
|
62
|
+
inputSchema: {
|
|
63
|
+
type: "object",
|
|
64
|
+
properties: { name: { type: "string" } },
|
|
65
|
+
required: ["name"],
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
({ name }) => `Hello, ${name}!`,
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
await server.start();
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### HTTP Server with Auth
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
import {
|
|
78
|
+
ConcurrentMCPServer,
|
|
79
|
+
createGoogleAuthProvider,
|
|
80
|
+
} from "@casys/mcp-server";
|
|
81
|
+
|
|
82
|
+
const server = new ConcurrentMCPServer({
|
|
83
|
+
name: "my-api",
|
|
84
|
+
version: "1.0.0",
|
|
85
|
+
maxConcurrent: 10,
|
|
86
|
+
backpressureStrategy: "queue",
|
|
87
|
+
validateSchema: true,
|
|
88
|
+
rateLimit: { maxRequests: 100, windowMs: 60_000 },
|
|
89
|
+
auth: {
|
|
90
|
+
provider: createGoogleAuthProvider({
|
|
91
|
+
audience: "https://my-mcp.example.com",
|
|
92
|
+
resource: "https://my-mcp.example.com",
|
|
93
|
+
}),
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
server.registerTool(
|
|
98
|
+
{
|
|
99
|
+
name: "query",
|
|
100
|
+
description: "Query the database",
|
|
101
|
+
inputSchema: {
|
|
102
|
+
type: "object",
|
|
103
|
+
properties: { sql: { type: "string" } },
|
|
104
|
+
},
|
|
105
|
+
requiredScopes: ["db:read"],
|
|
106
|
+
},
|
|
107
|
+
async ({ sql }) => ({ rows: [] }),
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
await server.startHttp({ port: 3000 });
|
|
111
|
+
// GET /health → { status: "ok" }
|
|
112
|
+
// GET /metrics → Prometheus text format
|
|
113
|
+
// POST /mcp → JSON-RPC (tools/call, tools/list, ...)
|
|
114
|
+
// GET /mcp → SSE stream (server→client notifications)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Secure-by-default HTTP options:**
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
await server.startHttp({
|
|
121
|
+
port: 3000,
|
|
122
|
+
requireAuth: true, // fail fast if auth isn't configured
|
|
123
|
+
corsOrigins: ["https://app.example.com"],
|
|
124
|
+
maxBodyBytes: 1_000_000, // 1 MB
|
|
125
|
+
ipRateLimit: { maxRequests: 120, windowMs: 60_000 },
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**Notes:**
|
|
130
|
+
|
|
131
|
+
- `requireAuth: true` throws if no auth provider is configured
|
|
132
|
+
- `corsOrigins` defaults to `"*"` — use an allowlist in production
|
|
133
|
+
- `maxBodyBytes` defaults to **1 MB** (set `null` to disable)
|
|
134
|
+
- `ipRateLimit` keys on client IP by default
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Features
|
|
139
|
+
|
|
140
|
+
### Middleware Pipeline
|
|
141
|
+
|
|
142
|
+
Composable onion model — same mental model as Hono, Koa, or Express.
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
import type { Middleware } from "@casys/mcp-server";
|
|
146
|
+
|
|
147
|
+
const timing: Middleware = async (ctx, next) => {
|
|
148
|
+
const start = performance.now();
|
|
149
|
+
const result = await next();
|
|
150
|
+
console.log(
|
|
151
|
+
`${ctx.toolName} took ${(performance.now() - start).toFixed(0)}ms`,
|
|
152
|
+
);
|
|
153
|
+
return result;
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
server.use(timing);
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Built-in pipeline: `rate-limit → auth → custom → scope-check → validation → backpressure → handler`
|
|
160
|
+
|
|
161
|
+
### OAuth2 / JWT Auth
|
|
162
|
+
|
|
163
|
+
Four OIDC presets out of the box:
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
import {
|
|
167
|
+
createGoogleAuthProvider, // Google OIDC
|
|
168
|
+
createAuth0AuthProvider, // Auth0
|
|
169
|
+
createGitHubAuthProvider, // GitHub Actions OIDC
|
|
170
|
+
createOIDCAuthProvider, // Generic OIDC (Keycloak, Okta, etc.)
|
|
171
|
+
} from "@casys/mcp-server";
|
|
172
|
+
|
|
173
|
+
const auth0 = createAuth0AuthProvider({
|
|
174
|
+
domain: "my-tenant.auth0.com",
|
|
175
|
+
audience: "https://my-mcp.example.com",
|
|
176
|
+
resource: "https://my-mcp.example.com",
|
|
177
|
+
scopesSupported: ["read", "write"],
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Or use `JwtAuthProvider` directly for custom setups:
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
import { JwtAuthProvider } from "@casys/mcp-server";
|
|
185
|
+
|
|
186
|
+
const provider = new JwtAuthProvider({
|
|
187
|
+
issuer: "https://my-idp.example.com",
|
|
188
|
+
audience: "https://my-mcp.example.com",
|
|
189
|
+
resource: "https://my-mcp.example.com",
|
|
190
|
+
authorizationServers: ["https://my-idp.example.com"],
|
|
191
|
+
});
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Token verification is cached (SHA-256 hash → AuthInfo, TTL = min(token expiry, 5min)) to avoid redundant JWKS round-trips.
|
|
195
|
+
|
|
196
|
+
### YAML + Env Config
|
|
197
|
+
|
|
198
|
+
For binary distribution — users configure auth without code:
|
|
199
|
+
|
|
200
|
+
```yaml
|
|
201
|
+
# mcp-server.yaml
|
|
202
|
+
auth:
|
|
203
|
+
provider: auth0
|
|
204
|
+
audience: https://my-mcp.example.com
|
|
205
|
+
resource: https://my-mcp.example.com
|
|
206
|
+
domain: my-tenant.auth0.com
|
|
207
|
+
scopesSupported: [read, write, admin]
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Env vars override YAML at deploy time:
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
MCP_AUTH_AUDIENCE=https://prod.example.com ./my-server --http --port 3000
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Priority: `programmatic > env vars > YAML > no auth`
|
|
217
|
+
|
|
218
|
+
### RFC 9728
|
|
219
|
+
|
|
220
|
+
When auth is configured, the framework automatically exposes `GET /.well-known/oauth-protected-resource` per [RFC 9728](https://www.rfc-editor.org/rfc/rfc9728).
|
|
221
|
+
|
|
222
|
+
### Observability
|
|
223
|
+
|
|
224
|
+
Every tool call emits an **OpenTelemetry span** with rich attributes:
|
|
225
|
+
|
|
226
|
+
```
|
|
227
|
+
mcp.tool.call query
|
|
228
|
+
mcp.tool.name = "query"
|
|
229
|
+
mcp.server.name = "my-api"
|
|
230
|
+
mcp.transport = "http"
|
|
231
|
+
mcp.session.id = "a1b2c3..."
|
|
232
|
+
mcp.tool.duration_ms = 42
|
|
233
|
+
mcp.tool.success = true
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Enable with Deno's native OTEL support:
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
OTEL_DENO=true deno run --unstable-otel server.ts
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
The HTTP server exposes a **Prometheus-compatible** `/metrics` endpoint:
|
|
243
|
+
|
|
244
|
+
```
|
|
245
|
+
mcp_server_tool_calls_total 1024
|
|
246
|
+
mcp_server_tool_calls_success_total 1018
|
|
247
|
+
mcp_server_tool_calls_failed_total 6
|
|
248
|
+
mcp_server_tool_call_duration_ms_bucket{le="50"} 892
|
|
249
|
+
mcp_server_tool_call_duration_ms_bucket{le="100"} 987
|
|
250
|
+
mcp_server_tool_calls_by_name{tool="query",status="success"} 512
|
|
251
|
+
mcp_server_active_requests 3
|
|
252
|
+
mcp_server_active_sessions 42
|
|
253
|
+
mcp_server_sse_clients 7
|
|
254
|
+
mcp_server_uptime_seconds 86400
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Programmatic access:
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
server.getServerMetrics(); // Full snapshot (counters, histograms, gauges)
|
|
261
|
+
server.getPrometheusMetrics(); // Prometheus text format string
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Concurrency Control
|
|
265
|
+
|
|
266
|
+
Three backpressure strategies when the server is at capacity:
|
|
267
|
+
|
|
268
|
+
| Strategy | Behavior |
|
|
269
|
+
| ----------------- | ------------------------------------------ |
|
|
270
|
+
| `sleep` (default) | Busy-wait with configurable sleep interval |
|
|
271
|
+
| `queue` | FIFO queue with ordered release |
|
|
272
|
+
| `reject` | Fail fast with immediate error |
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
new ConcurrentMCPServer({
|
|
276
|
+
maxConcurrent: 10,
|
|
277
|
+
backpressureStrategy: "queue",
|
|
278
|
+
});
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Rate Limiting
|
|
282
|
+
|
|
283
|
+
Sliding window rate limiter with per-client tracking:
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
new ConcurrentMCPServer({
|
|
287
|
+
rateLimit: {
|
|
288
|
+
maxRequests: 100,
|
|
289
|
+
windowMs: 60_000,
|
|
290
|
+
keyExtractor: (ctx) => ctx.args.clientId as string,
|
|
291
|
+
onLimitExceeded: "wait", // or "reject"
|
|
292
|
+
},
|
|
293
|
+
});
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
For HTTP endpoints, use `startHttp({ ipRateLimit: ... })` to rate limit by client IP (or custom key).
|
|
297
|
+
|
|
298
|
+
### Security Best Practices (Tool Handlers)
|
|
299
|
+
|
|
300
|
+
Tool handlers receive **untrusted JSON input**. Treat args as hostile:
|
|
301
|
+
|
|
302
|
+
- **Define strict schemas**: `additionalProperties: false`, `minLength`, `pattern`, `enum`.
|
|
303
|
+
- **Never pass raw args to a shell** (`Deno.Command`, `child_process.exec`). If you must, use an allowlist + argv array (no shell).
|
|
304
|
+
- **Validate paths & resources**: allowlisted roots, deny `..`, restrict env access.
|
|
305
|
+
- **Prefer safe APIs**: parameterized DB queries, SDK methods, typed clients.
|
|
306
|
+
- **Log sensitive actions**: file writes, network calls, admin ops.
|
|
307
|
+
|
|
308
|
+
### MCP Apps (UI Resources)
|
|
309
|
+
|
|
310
|
+
Register interactive UIs as MCP resources:
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
import { ConcurrentMCPServer, MCP_APP_MIME_TYPE } from "@casys/mcp-server";
|
|
314
|
+
|
|
315
|
+
server.registerResource(
|
|
316
|
+
{ uri: "ui://my-server/viewer", name: "Data Viewer" },
|
|
317
|
+
async (uri) => ({
|
|
318
|
+
uri: uri.toString(),
|
|
319
|
+
mimeType: MCP_APP_MIME_TYPE,
|
|
320
|
+
text: "<html><body>...</body></html>",
|
|
321
|
+
}),
|
|
322
|
+
);
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
---
|
|
326
|
+
|
|
327
|
+
## API Reference
|
|
328
|
+
|
|
329
|
+
### ConcurrentMCPServer
|
|
330
|
+
|
|
331
|
+
```typescript
|
|
332
|
+
const server = new ConcurrentMCPServer(options: ConcurrentServerOptions);
|
|
333
|
+
|
|
334
|
+
// Registration (before start)
|
|
335
|
+
server.registerTool(tool, handler);
|
|
336
|
+
server.registerTools(tools, handlers);
|
|
337
|
+
server.registerResource(resource, handler);
|
|
338
|
+
server.registerResources(resources, handlers);
|
|
339
|
+
server.use(middleware);
|
|
340
|
+
|
|
341
|
+
// Transport
|
|
342
|
+
await server.start(); // STDIO
|
|
343
|
+
await server.startHttp({ port: 3000 }); // HTTP + SSE
|
|
344
|
+
await server.stop(); // Graceful shutdown
|
|
345
|
+
|
|
346
|
+
// Observability
|
|
347
|
+
server.getMetrics(); // { inFlight, queued }
|
|
348
|
+
server.getServerMetrics(); // Full snapshot
|
|
349
|
+
server.getPrometheusMetrics(); // Prometheus text format
|
|
350
|
+
server.getRateLimitMetrics(); // { keys, totalRequests }
|
|
351
|
+
|
|
352
|
+
// Introspection
|
|
353
|
+
server.getToolCount();
|
|
354
|
+
server.getToolNames();
|
|
355
|
+
server.getResourceCount();
|
|
356
|
+
server.getResourceUris();
|
|
357
|
+
server.getSSEClientCount();
|
|
358
|
+
|
|
359
|
+
// SSE (Streamable HTTP)
|
|
360
|
+
server.sendToSession(sessionId, message);
|
|
361
|
+
server.broadcastNotification(method, params);
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### Standalone Components
|
|
365
|
+
|
|
366
|
+
Each component works independently:
|
|
367
|
+
|
|
368
|
+
```typescript
|
|
369
|
+
import { RateLimiter, RequestQueue, SchemaValidator } from "@casys/mcp-server";
|
|
370
|
+
|
|
371
|
+
// Rate limiter
|
|
372
|
+
const limiter = new RateLimiter({ maxRequests: 10, windowMs: 1000 });
|
|
373
|
+
if (limiter.checkLimit("client-123")) {
|
|
374
|
+
/* proceed */
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// Request queue
|
|
378
|
+
const queue = new RequestQueue({
|
|
379
|
+
maxConcurrent: 5,
|
|
380
|
+
strategy: "queue",
|
|
381
|
+
sleepMs: 10,
|
|
382
|
+
});
|
|
383
|
+
await queue.acquire();
|
|
384
|
+
try {
|
|
385
|
+
/* work */
|
|
386
|
+
} finally {
|
|
387
|
+
queue.release();
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// Schema validator
|
|
391
|
+
const validator = new SchemaValidator();
|
|
392
|
+
validator.addSchema("tool", {
|
|
393
|
+
type: "object",
|
|
394
|
+
properties: { n: { type: "number" } },
|
|
395
|
+
});
|
|
396
|
+
validator.validate("tool", { n: 5 }); // { valid: true, errors: [] }
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
---
|
|
400
|
+
|
|
401
|
+
## HTTP Endpoints
|
|
402
|
+
|
|
403
|
+
When running with `startHttp()`:
|
|
404
|
+
|
|
405
|
+
| Method | Path | Description |
|
|
406
|
+
| ------ | --------------------------------------- | ----------------------------------------------------------- |
|
|
407
|
+
| `POST` | `/mcp` or `/` | JSON-RPC endpoint (initialize, tools/call, tools/list, ...) |
|
|
408
|
+
| `GET` | `/mcp` or `/` | SSE stream (server→client notifications) |
|
|
409
|
+
| `GET` | `/health` | Health check |
|
|
410
|
+
| `GET` | `/metrics` | Prometheus metrics |
|
|
411
|
+
| `GET` | `/.well-known/oauth-protected-resource` | RFC 9728 metadata (when auth enabled) |
|
|
412
|
+
|
|
413
|
+
---
|
|
414
|
+
|
|
415
|
+
## License
|
|
416
|
+
|
|
417
|
+
MIT
|
package/mod.ts
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Concurrent Server Framework
|
|
3
|
+
*
|
|
4
|
+
* Production-ready MCP server framework with built-in concurrency control,
|
|
5
|
+
* backpressure strategies, and optional sampling support.
|
|
6
|
+
*
|
|
7
|
+
* Built on top of the official @modelcontextprotocol/sdk with added
|
|
8
|
+
* production features for reliability and performance.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { ConcurrentMCPServer } from "@casys/mcp-server";
|
|
13
|
+
*
|
|
14
|
+
* const server = new ConcurrentMCPServer({
|
|
15
|
+
* name: "my-server",
|
|
16
|
+
* version: "1.0.0",
|
|
17
|
+
* maxConcurrent: 10,
|
|
18
|
+
* backpressureStrategy: 'queue'
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* server.registerTool(
|
|
22
|
+
* { name: "greet", description: "Greet someone", inputSchema: { type: "object" } },
|
|
23
|
+
* (args) => `Hello, ${args.name}!`,
|
|
24
|
+
* );
|
|
25
|
+
*
|
|
26
|
+
* // STDIO transport
|
|
27
|
+
* await server.start();
|
|
28
|
+
*
|
|
29
|
+
* // — or — HTTP transport with security-first defaults
|
|
30
|
+
* const http = await server.startHttp({
|
|
31
|
+
* port: 3000,
|
|
32
|
+
* maxBodyBytes: 1_048_576, // 1 MB (default)
|
|
33
|
+
* corsOrigins: ["https://app.example.com"], // allowlist
|
|
34
|
+
* requireAuth: true, // fail-fast without auth
|
|
35
|
+
* ipRateLimit: { maxRequests: 60, windowMs: 60_000 },
|
|
36
|
+
* });
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @module @casys/mcp-server
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
// Main server class
|
|
43
|
+
export { ConcurrentMCPServer } from "./src/concurrent-server.js";
|
|
44
|
+
|
|
45
|
+
// Concurrency primitives
|
|
46
|
+
export { RequestQueue } from "./src/concurrency/request-queue.js";
|
|
47
|
+
|
|
48
|
+
// Rate limiting
|
|
49
|
+
export { RateLimiter } from "./src/concurrency/rate-limiter.js";
|
|
50
|
+
|
|
51
|
+
// Schema validation
|
|
52
|
+
export { SchemaValidator } from "./src/validation/schema-validator.js";
|
|
53
|
+
export type {
|
|
54
|
+
ValidationError,
|
|
55
|
+
ValidationResult,
|
|
56
|
+
} from "./src/validation/schema-validator.js";
|
|
57
|
+
|
|
58
|
+
// Sampling support
|
|
59
|
+
export { SamplingBridge } from "./src/sampling/sampling-bridge.js";
|
|
60
|
+
|
|
61
|
+
// Type exports
|
|
62
|
+
export type {
|
|
63
|
+
ConcurrentServerOptions,
|
|
64
|
+
HttpRateLimitContext,
|
|
65
|
+
HttpRateLimitOptions,
|
|
66
|
+
HttpServerInstance,
|
|
67
|
+
// HTTP Server types
|
|
68
|
+
HttpServerOptions,
|
|
69
|
+
// MCP Apps types (SEP-1865)
|
|
70
|
+
MCPResource,
|
|
71
|
+
MCPTool,
|
|
72
|
+
MCPToolMeta,
|
|
73
|
+
McpUiToolMeta,
|
|
74
|
+
QueueMetrics,
|
|
75
|
+
RateLimitContext,
|
|
76
|
+
RateLimitOptions,
|
|
77
|
+
ResourceContent,
|
|
78
|
+
ResourceHandler,
|
|
79
|
+
SamplingClient,
|
|
80
|
+
SamplingParams,
|
|
81
|
+
SamplingResult,
|
|
82
|
+
ToolHandler,
|
|
83
|
+
} from "./src/types.js";
|
|
84
|
+
|
|
85
|
+
// MCP Apps constants
|
|
86
|
+
export { MCP_APP_MIME_TYPE } from "./src/types.js";
|
|
87
|
+
|
|
88
|
+
// Middleware pipeline
|
|
89
|
+
export type {
|
|
90
|
+
Middleware,
|
|
91
|
+
MiddlewareContext,
|
|
92
|
+
MiddlewareResult,
|
|
93
|
+
NextFunction,
|
|
94
|
+
} from "./src/middleware/mod.js";
|
|
95
|
+
export { createMiddlewareRunner } from "./src/middleware/mod.js";
|
|
96
|
+
|
|
97
|
+
// Auth - Core
|
|
98
|
+
export { AuthProvider } from "./src/auth/mod.js";
|
|
99
|
+
export {
|
|
100
|
+
AuthError,
|
|
101
|
+
createAuthMiddleware,
|
|
102
|
+
createForbiddenResponse,
|
|
103
|
+
createUnauthorizedResponse,
|
|
104
|
+
extractBearerToken,
|
|
105
|
+
} from "./src/auth/mod.js";
|
|
106
|
+
export { createScopeMiddleware } from "./src/auth/mod.js";
|
|
107
|
+
export type {
|
|
108
|
+
AuthInfo,
|
|
109
|
+
AuthOptions,
|
|
110
|
+
ProtectedResourceMetadata,
|
|
111
|
+
} from "./src/auth/mod.js";
|
|
112
|
+
|
|
113
|
+
// Auth - JWT Provider + Presets
|
|
114
|
+
export { JwtAuthProvider } from "./src/auth/mod.js";
|
|
115
|
+
export type { JwtAuthProviderOptions } from "./src/auth/mod.js";
|
|
116
|
+
export {
|
|
117
|
+
createAuth0AuthProvider,
|
|
118
|
+
createGitHubAuthProvider,
|
|
119
|
+
createGoogleAuthProvider,
|
|
120
|
+
createOIDCAuthProvider,
|
|
121
|
+
} from "./src/auth/mod.js";
|
|
122
|
+
export type { PresetOptions } from "./src/auth/mod.js";
|
|
123
|
+
|
|
124
|
+
// Auth - Config (YAML + env)
|
|
125
|
+
export {
|
|
126
|
+
createAuthProviderFromConfig,
|
|
127
|
+
loadAuthConfig,
|
|
128
|
+
} from "./src/auth/mod.js";
|
|
129
|
+
export type { AuthConfig, AuthProviderName } from "./src/auth/mod.js";
|
|
130
|
+
|
|
131
|
+
// Observability
|
|
132
|
+
export {
|
|
133
|
+
endToolCallSpan,
|
|
134
|
+
getServerTracer,
|
|
135
|
+
isOtelEnabled,
|
|
136
|
+
recordAuthEvent,
|
|
137
|
+
ServerMetrics,
|
|
138
|
+
type ServerMetricsSnapshot,
|
|
139
|
+
startToolCallSpan,
|
|
140
|
+
type ToolCallSpanAttributes,
|
|
141
|
+
} from "./src/observability/mod.js";
|
|
142
|
+
|
|
143
|
+
// Security - CSP utilities
|
|
144
|
+
export { buildCspHeader, injectCspMetaTag } from "./src/security/csp.js";
|
|
145
|
+
export type { CspOptions } from "./src/security/csp.js";
|
|
146
|
+
|
|
147
|
+
// Security - HMAC channel authentication for PostMessage (MCP Apps)
|
|
148
|
+
export { injectChannelAuth } from "./src/security/channel-hmac.js";
|
|
149
|
+
export { MessageSigner } from "./src/security/message-signer.js";
|
|
150
|
+
export type {
|
|
151
|
+
SignedMessage,
|
|
152
|
+
VerifyResult,
|
|
153
|
+
} from "./src/security/message-signer.js";
|
|
154
|
+
|
|
155
|
+
// Runtime port (for advanced consumers who need to inspect the adapter contract)
|
|
156
|
+
export type {
|
|
157
|
+
FetchHandler,
|
|
158
|
+
RuntimePort,
|
|
159
|
+
ServeHandle,
|
|
160
|
+
ServeOptions,
|
|
161
|
+
} from "./src/runtime/types.js";
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@casys/mcp-server",
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "Production-ready MCP server framework with concurrency control, auth, and observability",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "mod.ts",
|
|
7
|
+
"types": "mod.ts",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "tsc",
|
|
10
|
+
"test": "tsx --test src/**/*_test.ts"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@modelcontextprotocol/sdk": "^1.15.1",
|
|
14
|
+
"hono": "^4.0.0",
|
|
15
|
+
"ajv": "^8.17.1",
|
|
16
|
+
"jose": "^6.0.0",
|
|
17
|
+
"yaml": "^2.7.0",
|
|
18
|
+
"@opentelemetry/api": "^1.9.0"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"typescript": "^5.4.0",
|
|
22
|
+
"tsx": "^4.0.0"
|
|
23
|
+
},
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=20.0.0"
|
|
26
|
+
},
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/Casys-AI/mcp-server"
|
|
30
|
+
},
|
|
31
|
+
"license": "MIT"
|
|
32
|
+
}
|