veryfront 0.1.159 → 0.1.162

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 (51) hide show
  1. package/esm/deno.js +1 -1
  2. package/esm/src/agent/index.d.ts +1 -1
  3. package/esm/src/agent/index.d.ts.map +1 -1
  4. package/esm/src/agent/runtime/index.d.ts +2 -12
  5. package/esm/src/agent/runtime/index.d.ts.map +1 -1
  6. package/esm/src/agent/runtime/index.js +62 -25
  7. package/esm/src/agent/types.d.ts +37 -0
  8. package/esm/src/agent/types.d.ts.map +1 -1
  9. package/esm/src/mcp/http-transport.d.ts +33 -0
  10. package/esm/src/mcp/http-transport.d.ts.map +1 -0
  11. package/esm/src/mcp/http-transport.js +97 -0
  12. package/esm/src/mcp/server.d.ts.map +1 -1
  13. package/esm/src/mcp/server.js +14 -107
  14. package/esm/src/platform/adapters/fs/veryfront/base-operations.d.ts +1 -1
  15. package/esm/src/platform/adapters/fs/veryfront/base-operations.d.ts.map +1 -1
  16. package/esm/src/platform/adapters/fs/veryfront/directory-operations.d.ts.map +1 -1
  17. package/esm/src/platform/adapters/fs/veryfront/directory-operations.js +9 -52
  18. package/esm/src/platform/adapters/fs/veryfront/file-list-access.d.ts +33 -0
  19. package/esm/src/platform/adapters/fs/veryfront/file-list-access.d.ts.map +1 -0
  20. package/esm/src/platform/adapters/fs/veryfront/file-list-access.js +49 -0
  21. package/esm/src/platform/adapters/fs/veryfront/read-operations.d.ts +1 -20
  22. package/esm/src/platform/adapters/fs/veryfront/read-operations.d.ts.map +1 -1
  23. package/esm/src/platform/adapters/fs/veryfront/stat-operations.d.ts.map +1 -1
  24. package/esm/src/platform/adapters/fs/veryfront/stat-operations.js +21 -94
  25. package/esm/src/tool/factory.d.ts +3 -5
  26. package/esm/src/tool/factory.d.ts.map +1 -1
  27. package/esm/src/tool/factory.js +2 -1
  28. package/esm/src/tool/index.d.ts +2 -0
  29. package/esm/src/tool/index.d.ts.map +1 -1
  30. package/esm/src/tool/index.js +1 -0
  31. package/esm/src/tool/remote-source-tools.d.ts +8 -0
  32. package/esm/src/tool/remote-source-tools.d.ts.map +1 -0
  33. package/esm/src/tool/remote-source-tools.js +33 -0
  34. package/esm/src/utils/version-constant.d.ts +1 -1
  35. package/esm/src/utils/version-constant.js +1 -1
  36. package/package.json +1 -1
  37. package/src/deno.js +1 -1
  38. package/src/src/agent/index.ts +6 -0
  39. package/src/src/agent/runtime/index.ts +118 -11
  40. package/src/src/agent/types.ts +47 -0
  41. package/src/src/mcp/http-transport.ts +163 -0
  42. package/src/src/mcp/server.ts +15 -123
  43. package/src/src/platform/adapters/fs/veryfront/base-operations.ts +1 -1
  44. package/src/src/platform/adapters/fs/veryfront/directory-operations.ts +10 -75
  45. package/src/src/platform/adapters/fs/veryfront/file-list-access.ts +109 -0
  46. package/src/src/platform/adapters/fs/veryfront/read-operations.ts +1 -22
  47. package/src/src/platform/adapters/fs/veryfront/stat-operations.ts +27 -120
  48. package/src/src/tool/factory.ts +4 -6
  49. package/src/src/tool/index.ts +5 -0
  50. package/src/src/tool/remote-source-tools.ts +54 -0
  51. package/src/src/utils/version-constant.ts +1 -1
@@ -0,0 +1,33 @@
1
+ import { z } from "zod";
2
+ import { dynamicTool } from "./factory.js";
3
+ function toToolInputRecord(input) {
4
+ if (typeof input !== "object" || input === null || Array.isArray(input)) {
5
+ return {};
6
+ }
7
+ return Object.fromEntries(Object.entries(input));
8
+ }
9
+ export function createToolsFromRemoteDefinitions(source, definitions, options = {}) {
10
+ return Object.fromEntries(definitions.map((definition) => {
11
+ const toolName = options.toolNameAliases?.[definition.name] ?? definition.name;
12
+ return [
13
+ toolName,
14
+ dynamicTool({
15
+ id: toolName,
16
+ description: definition.description,
17
+ inputSchema: z.object({}).passthrough(),
18
+ inputSchemaJson: definition.parameters,
19
+ mcp: {
20
+ title: definition.title,
21
+ annotations: definition.annotations,
22
+ },
23
+ execute: async (input, context) => await source.executeTool(definition.name, toToolInputRecord(input), context),
24
+ }),
25
+ ];
26
+ }));
27
+ }
28
+ export async function loadRemoteToolsFromSource(source, options = {}) {
29
+ const definitions = await source.listTools(options.context);
30
+ return createToolsFromRemoteDefinitions(source, definitions, {
31
+ toolNameAliases: options.toolNameAliases,
32
+ });
33
+ }
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.1.159";
1
+ export declare const VERSION = "0.1.162";
2
2
  //# sourceMappingURL=version-constant.d.ts.map
@@ -1,3 +1,3 @@
1
1
  // Keep in sync with deno.json version.
2
2
  // scripts/release.ts updates this constant during releases.
3
- export const VERSION = "0.1.159";
3
+ export const VERSION = "0.1.162";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veryfront",
3
- "version": "0.1.159",
3
+ "version": "0.1.162",
4
4
  "description": "The simplest way to build AI-powered apps",
5
5
  "keywords": [
6
6
  "react",
package/src/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.159",
3
+ "version": "0.1.162",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "exclude": [
@@ -97,7 +97,13 @@ export type {
97
97
  MessagePart,
98
98
  ModelProvider,
99
99
  ModelString,
100
+ ModelTransportRequest,
101
+ ModelTransportResolver,
100
102
  ResolvedAgentConfig,
103
+ ResolvedModelTransport,
104
+ ResolvedRuntimeState,
105
+ RuntimeStateRequest,
106
+ RuntimeStateResolver,
101
107
  StreamToolCall,
102
108
  ToolCall,
103
109
  ToolCallPart,
@@ -10,6 +10,8 @@
10
10
  *
11
11
  * @module ai/agent/runtime
12
12
  */
13
+ import * as dntShim from "../../../_dnt.shims.js";
14
+
13
15
 
14
16
  import {
15
17
  type AgentConfig,
@@ -19,6 +21,7 @@ import {
19
21
  getTextFromParts,
20
22
  type Message,
21
23
  type MessagePart,
24
+ type ResolvedRuntimeState,
22
25
  type ToolCall,
23
26
  type ToolResultPart,
24
27
  } from "../types.js";
@@ -264,6 +267,19 @@ function getRuntimeAllowedRemoteTools(config: AgentConfig): string[] | undefined
264
267
  return raw.every((toolName) => typeof toolName === "string") ? raw : [];
265
268
  }
266
269
 
270
+ type ResolvedModelTransport = {
271
+ requestedModel: string;
272
+ resolvedModelString: string;
273
+ languageModel: ModelRuntime;
274
+ headers?: dntShim.HeadersInit;
275
+ providerOptions?: Record<string, unknown>;
276
+ };
277
+
278
+ type RuntimeStepState = {
279
+ systemPrompt: string;
280
+ context?: Record<string, unknown>;
281
+ };
282
+
267
283
  export class AgentRuntime {
268
284
  private id: string;
269
285
  private config: AgentConfig;
@@ -279,6 +295,52 @@ export class AgentRuntime {
279
295
  this.memory = createMemory<Message>(memoryConfig);
280
296
  }
281
297
 
298
+ private async resolveModelTransport(
299
+ context: Record<string, unknown> | undefined,
300
+ modelOverride: string | undefined,
301
+ mode: "generate" | "stream",
302
+ ): Promise<ResolvedModelTransport> {
303
+ const requestedModel = resolveConfiguredAgentModel(modelOverride || this.config.model);
304
+ const resolvedModelString = resolveRuntimeModel(modelOverride || this.config.model);
305
+ const transport = await this.config.resolveModelTransport?.({
306
+ agentId: this.id,
307
+ requestedModel,
308
+ resolvedModel: resolvedModelString,
309
+ context,
310
+ mode,
311
+ });
312
+
313
+ return {
314
+ requestedModel,
315
+ resolvedModelString,
316
+ languageModel: transport?.model ?? resolveModel(resolvedModelString),
317
+ headers: transport?.headers,
318
+ providerOptions: transport?.providerOptions,
319
+ };
320
+ }
321
+
322
+ private async resolveRuntimeState(
323
+ messages: Message[],
324
+ context: Record<string, unknown> | undefined,
325
+ mode: "generate" | "stream",
326
+ step: number,
327
+ systemPrompt: string,
328
+ ): Promise<RuntimeStepState> {
329
+ const refreshed: ResolvedRuntimeState | undefined = await this.config.resolveRuntimeState?.({
330
+ agentId: this.id,
331
+ mode,
332
+ step,
333
+ system: systemPrompt,
334
+ messages: [...messages],
335
+ context,
336
+ });
337
+
338
+ return {
339
+ systemPrompt: refreshed?.system ?? systemPrompt,
340
+ context: refreshed?.context ?? context,
341
+ };
342
+ }
343
+
282
344
  /**
283
345
  * Generate a response (non-streaming)
284
346
  */
@@ -288,8 +350,9 @@ export class AgentRuntime {
288
350
  modelOverride?: string,
289
351
  maxOutputTokensOverride?: number,
290
352
  ): Promise<AgentResponse> {
291
- const requestedModel = resolveConfiguredAgentModel(modelOverride || this.config.model);
292
- const resolvedModelString = resolveRuntimeModel(modelOverride || this.config.model);
353
+ const transport = await this.resolveModelTransport(context, modelOverride, "generate");
354
+ const requestedModel = transport.requestedModel;
355
+ const resolvedModelString = transport.resolvedModelString;
293
356
  if (resolvedModelString !== requestedModel) {
294
357
  logger.info(
295
358
  `⚡ Using runtime model "${resolvedModelString}" instead of "${requestedModel}".`,
@@ -326,9 +389,12 @@ export class AgentRuntime {
326
389
  {
327
390
  agentId: this.id,
328
391
  projectId: tryGetCacheKeyContext()?.projectId,
329
- ...context,
330
392
  },
393
+ context,
331
394
  resolvedModelString,
395
+ transport.languageModel,
396
+ transport.headers,
397
+ transport.providerOptions,
332
398
  maxOutputTokensOverride,
333
399
  ),
334
400
  );
@@ -351,8 +417,9 @@ export class AgentRuntime {
351
417
  maxOutputTokensOverride?: number,
352
418
  abortSignal?: AbortSignal,
353
419
  ): Promise<ReadableStream<Uint8Array>> {
354
- const requestedModel = resolveConfiguredAgentModel(modelOverride || this.config.model);
355
- const resolvedModelString = resolveRuntimeModel(modelOverride || this.config.model);
420
+ const transport = await this.resolveModelTransport(context, modelOverride, "stream");
421
+ const requestedModel = transport.requestedModel;
422
+ const resolvedModelString = transport.resolvedModelString;
356
423
  if (resolvedModelString !== requestedModel) {
357
424
  logger.info(
358
425
  `⚡ Using runtime model "${resolvedModelString}" instead of "${requestedModel}".`,
@@ -389,7 +456,7 @@ export class AgentRuntime {
389
456
  // Resolve model BEFORE creating the ReadableStream — if this throws
390
457
  // (e.g., no_ai_available), the error propagates to the caller who can
391
458
  // return a proper error response (503) instead of a 200 with an error event.
392
- const languageModel = resolveModel(resolvedModelString);
459
+ const languageModel = transport.languageModel;
393
460
 
394
461
  // Determine inference mode from the resolved model object (not the string),
395
462
  // because resolveModel may internally fall back from cloud to local.
@@ -433,8 +500,11 @@ export class AgentRuntime {
433
500
  callbacks,
434
501
  textPartId,
435
502
  toolContext,
503
+ context,
436
504
  resolvedModelString,
437
505
  languageModel,
506
+ transport.headers,
507
+ transport.providerOptions,
438
508
  maxOutputTokensOverride,
439
509
  streamAbortSignal,
440
510
  );
@@ -474,15 +544,19 @@ export class AgentRuntime {
474
544
  private async executeAgentLoop(
475
545
  systemPrompt: string,
476
546
  messages: Message[],
477
- toolContext?: ToolExecutionContext,
547
+ toolContextBase?: ToolExecutionContext,
548
+ runtimeContext?: Record<string, unknown>,
478
549
  modelString?: string,
550
+ resolvedModel?: ModelRuntime,
551
+ headers?: dntShim.HeadersInit,
552
+ providerOptions?: Record<string, unknown>,
479
553
  maxOutputTokensOverride?: number,
480
554
  ): Promise<AgentResponse> {
481
555
  return withSpan("agent.execution_loop", async (loopSpan) => {
482
556
  const { maxAgentSteps } = getPlatformCapabilities();
483
557
  const maxSteps = this.computeMaxSteps(maxAgentSteps);
484
558
  const effectiveModel = resolveRuntimeModel(modelString || this.config.model);
485
- const languageModel = resolveModel(effectiveModel);
559
+ const languageModel = resolvedModel ?? resolveModel(effectiveModel);
486
560
 
487
561
  const toolCalls: ToolCall[] = [];
488
562
  const currentMessages = [...messages];
@@ -502,11 +576,24 @@ export class AgentRuntime {
502
576
  // Request-scoped skill policy (not class-level mutable state)
503
577
  let activeSkillPolicy: string[] | undefined;
504
578
  const allowedRemoteToolNames = getRuntimeAllowedRemoteTools(this.config);
579
+ let currentSystemPrompt = systemPrompt;
580
+ let currentRuntimeContext = runtimeContext;
505
581
 
506
582
  for (let step = 0; step < maxSteps; step++) {
507
583
  this.status = "thinking";
508
584
  addSpanEvent(loopSpan, "step_start", { step });
509
585
 
586
+ const runtimeState = await this.resolveRuntimeState(
587
+ currentMessages,
588
+ currentRuntimeContext,
589
+ "generate",
590
+ step,
591
+ currentSystemPrompt,
592
+ );
593
+ currentSystemPrompt = runtimeState.systemPrompt;
594
+ currentRuntimeContext = runtimeState.context;
595
+ const toolContext = { ...toolContextBase, ...currentRuntimeContext };
596
+
510
597
  let tools = isLocal ? [] : await getAvailableTools(this.config.tools, {
511
598
  includeSkillTools: Boolean(this.config.skills),
512
599
  allowedRemoteToolNames,
@@ -526,7 +613,7 @@ export class AgentRuntime {
526
613
  });
527
614
  return generateText({
528
615
  model: languageModel,
529
- system: systemPrompt,
616
+ system: currentSystemPrompt,
530
617
  messages: convertToModelMessages(currentMessages),
531
618
  tools: convertToolsToRuntimeTools(tools, {
532
619
  model: effectiveModel,
@@ -535,6 +622,8 @@ export class AgentRuntime {
535
622
  experimental_repairToolCall: repairToolCall,
536
623
  maxOutputTokens: this.resolveMaxOutputTokens(maxOutputTokensOverride),
537
624
  temperature: DEFAULT_TEMPERATURE,
625
+ ...(headers ? { headers } : {}),
626
+ ...(providerOptions ? { providerOptions } : {}),
538
627
  });
539
628
  });
540
629
 
@@ -764,9 +853,12 @@ export class AgentRuntime {
764
853
  onFinish?: (response: AgentResponse) => void;
765
854
  },
766
855
  textPartId?: string,
767
- toolContext?: Record<string, unknown>,
856
+ toolContextBase?: Record<string, unknown>,
857
+ runtimeContext?: Record<string, unknown>,
768
858
  modelString?: string,
769
859
  resolvedModel?: ModelRuntime,
860
+ headers?: dntShim.HeadersInit,
861
+ providerOptions?: Record<string, unknown>,
770
862
  maxOutputTokensOverride?: number,
771
863
  abortSignal?: AbortSignal,
772
864
  ): Promise<AgentResponse> {
@@ -795,12 +887,25 @@ export class AgentRuntime {
795
887
  let finalFinishReason: string | undefined;
796
888
  let latestAssistantText = "";
797
889
  const allowedRemoteToolNames = getRuntimeAllowedRemoteTools(this.config);
890
+ let currentSystemPrompt = systemPrompt;
891
+ let currentRuntimeContext = runtimeContext;
798
892
 
799
893
  for (let step = 0; step < maxSteps; step++) {
800
894
  throwIfAborted(abortSignal);
801
895
  sendSSE(controller, encoder, { type: "step-start" });
802
896
  const currentStepToolResults = new Map<string, ToolResultPart>();
803
897
 
898
+ const runtimeState = await this.resolveRuntimeState(
899
+ currentMessages,
900
+ currentRuntimeContext,
901
+ "stream",
902
+ step,
903
+ currentSystemPrompt,
904
+ );
905
+ currentSystemPrompt = runtimeState.systemPrompt;
906
+ currentRuntimeContext = runtimeState.context;
907
+ const toolContext = { ...toolContextBase, ...currentRuntimeContext };
908
+
804
909
  let tools = isLocalStreaming ? [] : await getAvailableTools(this.config.tools, {
805
910
  includeSkillTools: Boolean(this.config.skills),
806
911
  allowedRemoteToolNames,
@@ -815,7 +920,7 @@ export class AgentRuntime {
815
920
 
816
921
  const result = streamText({
817
922
  model: languageModel,
818
- system: systemPrompt,
923
+ system: currentSystemPrompt,
819
924
  messages: convertToModelMessages(currentMessages),
820
925
  tools: convertToolsToRuntimeTools(tools, {
821
926
  model: effectiveModel,
@@ -824,6 +929,8 @@ export class AgentRuntime {
824
929
  experimental_repairToolCall: repairToolCall,
825
930
  maxOutputTokens: this.resolveMaxOutputTokens(maxOutputTokensOverride),
826
931
  temperature: DEFAULT_TEMPERATURE,
932
+ ...(headers ? { headers } : {}),
933
+ ...(providerOptions ? { providerOptions } : {}),
827
934
  abortSignal,
828
935
  });
829
936
 
@@ -4,6 +4,7 @@
4
4
  import * as dntShim from "../../_dnt.shims.js";
5
5
 
6
6
 
7
+ import type { ModelRuntime } from "../provider/types.js";
7
8
  import type { RemoteToolSource, Tool } from "../tool/index.js";
8
9
  import { INVALID_ARGUMENT } from "../errors/error-registry.js";
9
10
  import type { Memory } from "./memory/memory-interface.js";
@@ -91,6 +92,16 @@ export interface AgentConfig {
91
92
  };
92
93
  /** Restrict runtime model overrides to these "provider/model" strings. */
93
94
  allowedModels?: ModelString[];
95
+ /**
96
+ * Optional request-aware hook for overriding the resolved model runtime and
97
+ * provider transport options on a per-call basis.
98
+ */
99
+ resolveModelTransport?: ModelTransportResolver;
100
+ /**
101
+ * Optional step-boundary hook for refreshing the runtime system prompt and
102
+ * host-owned context during a long-lived run.
103
+ */
104
+ resolveRuntimeState?: RuntimeStateResolver;
94
105
  /**
95
106
  * Enable skills for this agent.
96
107
  * - true: include all discovered skills from skills/ directory
@@ -108,6 +119,42 @@ export interface AgentConfig {
108
119
 
109
120
  export type ResolvedAgentConfig = AgentConfig & { model: ModelString };
110
121
 
122
+ export interface ModelTransportRequest {
123
+ agentId: string;
124
+ requestedModel: ModelString;
125
+ resolvedModel: ModelString;
126
+ context?: Record<string, unknown>;
127
+ mode: "generate" | "stream";
128
+ }
129
+
130
+ export interface ResolvedModelTransport {
131
+ model?: ModelRuntime;
132
+ headers?: dntShim.HeadersInit;
133
+ providerOptions?: Record<string, unknown>;
134
+ }
135
+
136
+ export type ModelTransportResolver = (
137
+ request: ModelTransportRequest,
138
+ ) => ResolvedModelTransport | Promise<ResolvedModelTransport>;
139
+
140
+ export interface RuntimeStateRequest {
141
+ agentId: string;
142
+ mode: "generate" | "stream";
143
+ step: number;
144
+ system: string;
145
+ messages: Message[];
146
+ context?: Record<string, unknown>;
147
+ }
148
+
149
+ export interface ResolvedRuntimeState {
150
+ system?: string;
151
+ context?: Record<string, unknown>;
152
+ }
153
+
154
+ export type RuntimeStateResolver = (
155
+ request: RuntimeStateRequest,
156
+ ) => ResolvedRuntimeState | undefined | Promise<ResolvedRuntimeState | undefined>;
157
+
111
158
  // Import for use in AgentMiddleware
112
159
  import type { AgentContext, AgentResponse } from "./schemas/index.js";
113
160
 
@@ -0,0 +1,163 @@
1
+ import * as dntShim from "../../_dnt.shims.js";
2
+ import type { ToolExecutionContext } from "../tool/index.js";
3
+ import { VeryfrontError } from "../security/input-validation/errors.js";
4
+ import { validateContentType } from "../security/input-validation/limits.js";
5
+ import { SessionManager } from "./session.js";
6
+
7
+ const MAX_REQUEST_BODY_SIZE = 1_048_576; // 1 MB
8
+ const JSON_CONTENT_TYPE = "application/json";
9
+
10
+ type JSONRPCParams = Record<string, unknown> | unknown[];
11
+
12
+ interface JSONRPCRequest {
13
+ jsonrpc: "2.0";
14
+ id?: string | number;
15
+ method: string;
16
+ params?: JSONRPCParams;
17
+ }
18
+
19
+ interface JSONRPCResponse {
20
+ jsonrpc: "2.0";
21
+ id?: string | number;
22
+ result?: unknown;
23
+ error?: {
24
+ code: number;
25
+ message: string;
26
+ data?: unknown;
27
+ };
28
+ }
29
+
30
+ export interface MCPHTTPTransportDependencies {
31
+ authEnabled: boolean;
32
+ getCORSHeaders: (requestOrigin?: string | null) => Record<string, string>;
33
+ validateAuth: (request: dntShim.Request) => Promise<boolean>;
34
+ handleRequest: (
35
+ request: JSONRPCRequest,
36
+ context?: ToolExecutionContext,
37
+ ) => Promise<JSONRPCResponse>;
38
+ extractRequestContext: (request: dntShim.Request) => ToolExecutionContext | undefined;
39
+ isOriginAllowed: (requestOrigin?: string | null) => boolean;
40
+ sessionCapabilities: Map<string, Record<string, unknown>>;
41
+ sessionManager: SessionManager;
42
+ }
43
+
44
+ function createJSONResponse(body: unknown, init?: dntShim.ResponseInit): dntShim.Response {
45
+ const headers = new dntShim.Headers(init?.headers);
46
+ headers.set("Content-Type", JSON_CONTENT_TYPE);
47
+ return new dntShim.Response(JSON.stringify(body), { ...init, headers });
48
+ }
49
+
50
+ function createJSONRPCErrorResponse(status: number, code: number, message: string): dntShim.Response {
51
+ return createJSONResponse(
52
+ {
53
+ jsonrpc: "2.0",
54
+ id: null,
55
+ error: { code, message },
56
+ },
57
+ { status },
58
+ );
59
+ }
60
+
61
+ export function createMCPHTTPHandler(
62
+ dependencies: MCPHTTPTransportDependencies,
63
+ ): (request: dntShim.Request) => Promise<dntShim.Response> {
64
+ const {
65
+ authEnabled,
66
+ getCORSHeaders,
67
+ validateAuth,
68
+ handleRequest,
69
+ extractRequestContext,
70
+ isOriginAllowed,
71
+ sessionCapabilities,
72
+ sessionManager,
73
+ } = dependencies;
74
+
75
+ return async (request: dntShim.Request) => {
76
+ const requestOrigin = request.headers.get("Origin");
77
+
78
+ if (request.method === "OPTIONS") {
79
+ return new dntShim.Response(null, { status: 204, headers: getCORSHeaders(requestOrigin) });
80
+ }
81
+
82
+ if (!isOriginAllowed(requestOrigin)) {
83
+ return createJSONRPCErrorResponse(403, -32600, "Forbidden: Origin not allowed");
84
+ }
85
+
86
+ if (authEnabled) {
87
+ const authorized = await validateAuth(request);
88
+ if (!authorized) return new dntShim.Response("Unauthorized", { status: 401 });
89
+ }
90
+
91
+ if (request.method === "DELETE") {
92
+ const sessionId = request.headers.get("MCP-Session-Id");
93
+ if (sessionId) {
94
+ sessionManager.terminate(sessionId);
95
+ sessionCapabilities.delete(sessionId);
96
+ }
97
+ return new dntShim.Response(null, { status: 200, headers: getCORSHeaders(requestOrigin) });
98
+ }
99
+
100
+ if (request.method !== "POST") {
101
+ return new dntShim.Response("Method Not Allowed", { status: 405 });
102
+ }
103
+
104
+ const contentLength = request.headers.get("content-length");
105
+ if (contentLength && Number(contentLength) > MAX_REQUEST_BODY_SIZE) {
106
+ return createJSONRPCErrorResponse(413, -32600, "Request body too large");
107
+ }
108
+
109
+ try {
110
+ validateContentType(request, JSON_CONTENT_TYPE);
111
+ } catch (error) {
112
+ const message = error instanceof VeryfrontError ? error.message : "Invalid Content-Type";
113
+ return createJSONRPCErrorResponse(400, -32700, message);
114
+ }
115
+
116
+ let rpcRequest: JSONRPCRequest;
117
+ try {
118
+ const bodyText = await request.text();
119
+ if (bodyText.length > MAX_REQUEST_BODY_SIZE) {
120
+ return createJSONRPCErrorResponse(413, -32600, "Request body too large");
121
+ }
122
+ rpcRequest = JSON.parse(bodyText) as JSONRPCRequest;
123
+ } catch (_) {
124
+ return createJSONRPCErrorResponse(400, -32700, "Parse error");
125
+ }
126
+
127
+ const responseHeaders: Record<string, string> = {
128
+ ...getCORSHeaders(requestOrigin),
129
+ };
130
+
131
+ if (rpcRequest.method === "initialize") {
132
+ const context = extractRequestContext(request);
133
+ const rpcResponse = await handleRequest(rpcRequest, context);
134
+ const clientCaps =
135
+ ((rpcRequest.params as Record<string, unknown> | undefined)?.capabilities ??
136
+ {}) as Record<string, unknown>;
137
+ const sessionId = sessionManager.create();
138
+ sessionCapabilities.set(sessionId, clientCaps);
139
+ responseHeaders["MCP-Session-Id"] = sessionId;
140
+ return createJSONResponse(rpcResponse, { headers: responseHeaders });
141
+ }
142
+
143
+ if (sessionManager.size > 0) {
144
+ const sessionId = request.headers.get("MCP-Session-Id");
145
+ if (!sessionId) {
146
+ return createJSONRPCErrorResponse(400, -32600, "Missing MCP-Session-Id header");
147
+ }
148
+ if (!sessionManager.isValid(sessionId)) {
149
+ return createJSONRPCErrorResponse(404, -32600, "Session not found or expired");
150
+ }
151
+ }
152
+
153
+ if (rpcRequest.id === undefined) {
154
+ const context = extractRequestContext(request);
155
+ await handleRequest(rpcRequest, context);
156
+ return new dntShim.Response(null, { status: 202, headers: responseHeaders });
157
+ }
158
+
159
+ const context = extractRequestContext(request);
160
+ const rpcResponse = await handleRequest(rpcRequest, context);
161
+ return createJSONResponse(rpcResponse, { headers: responseHeaders });
162
+ };
163
+ }