veryfront 0.1.140 → 0.1.142
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/esm/cli/mcp/jsonrpc.d.ts +33 -1
- package/esm/cli/mcp/jsonrpc.d.ts.map +1 -1
- package/esm/cli/mcp/jsonrpc.js +63 -4
- package/esm/cli/mcp/remote-file-tools.d.ts.map +1 -1
- package/esm/cli/mcp/remote-file-tools.js +39 -0
- package/esm/cli/mcp/server.d.ts.map +1 -1
- package/esm/cli/mcp/server.js +57 -34
- package/esm/cli/mcp/standalone.d.ts.map +1 -1
- package/esm/cli/mcp/standalone.js +24 -11
- package/esm/cli/mcp/tools/catalog-tools.d.ts.map +1 -1
- package/esm/cli/mcp/tools/catalog-tools.js +15 -5
- package/esm/cli/mcp/tools/cicd-tools.d.ts.map +1 -1
- package/esm/cli/mcp/tools/cicd-tools.js +8 -0
- package/esm/cli/mcp/tools/dev-tools.d.ts.map +1 -1
- package/esm/cli/mcp/tools/dev-tools.js +32 -10
- package/esm/cli/mcp/tools/introspection-tools.d.ts.map +1 -1
- package/esm/cli/mcp/tools/introspection-tools.js +6 -2
- package/esm/cli/mcp/tools/project-tools.d.ts.map +1 -1
- package/esm/cli/mcp/tools/project-tools.js +12 -4
- package/esm/cli/mcp/tools/scaffold-tools.d.ts.map +1 -1
- package/esm/cli/mcp/tools/scaffold-tools.js +6 -2
- package/esm/cli/mcp/tools/skill-tools.d.ts.map +1 -1
- package/esm/cli/mcp/tools/skill-tools.js +6 -2
- package/esm/cli/mcp/tools.d.ts.map +1 -1
- package/esm/cli/mcp/tools.js +36 -16
- package/esm/deno.js +1 -1
- package/esm/src/agent/runtime/index.js +1 -1
- package/esm/src/agent/runtime/tool-helpers.d.ts.map +1 -1
- package/esm/src/agent/runtime/tool-helpers.js +59 -30
- package/esm/src/agent/schemas/agent.schema.d.ts +4 -4
- package/esm/src/channels/invoke.d.ts +4 -4
- package/esm/src/internal-agents/run-stream.d.ts.map +1 -1
- package/esm/src/internal-agents/run-stream.js +62 -0
- package/esm/src/issues/mcp.d.ts.map +1 -1
- package/esm/src/issues/mcp.js +39 -10
- package/esm/src/mcp/index.d.ts +1 -1
- package/esm/src/mcp/index.d.ts.map +1 -1
- package/esm/src/mcp/server.d.ts.map +1 -1
- package/esm/src/mcp/server.js +85 -25
- package/esm/src/mcp/types.d.ts +22 -0
- package/esm/src/mcp/types.d.ts.map +1 -1
- package/esm/src/server/handlers/request/agent-stream.handler.d.ts.map +1 -1
- package/esm/src/server/handlers/request/agent-stream.handler.js +30 -0
- package/esm/src/tool/types.d.ts +5 -0
- package/esm/src/tool/types.d.ts.map +1 -1
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/esm/src/workflow/schemas/workflow.schema.d.ts +6 -6
- package/package.json +1 -1
- package/src/cli/mcp/jsonrpc.ts +72 -4
- package/src/cli/mcp/remote-file-tools.ts +39 -0
- package/src/cli/mcp/server.ts +66 -33
- package/src/cli/mcp/standalone.ts +28 -10
- package/src/cli/mcp/tools/catalog-tools.ts +15 -5
- package/src/cli/mcp/tools/cicd-tools.ts +8 -0
- package/src/cli/mcp/tools/dev-tools.ts +34 -10
- package/src/cli/mcp/tools/introspection-tools.ts +7 -2
- package/src/cli/mcp/tools/project-tools.ts +12 -4
- package/src/cli/mcp/tools/scaffold-tools.ts +6 -2
- package/src/cli/mcp/tools/skill-tools.ts +6 -2
- package/src/cli/mcp/tools.ts +52 -16
- package/src/deno.js +1 -1
- package/src/src/agent/runtime/index.ts +1 -1
- package/src/src/agent/runtime/tool-helpers.ts +86 -36
- package/src/src/internal-agents/run-stream.ts +62 -0
- package/src/src/issues/mcp.ts +43 -10
- package/src/src/mcp/index.ts +7 -1
- package/src/src/mcp/server.ts +92 -31
- package/src/src/mcp/types.ts +24 -0
- package/src/src/server/handlers/request/agent-stream.handler.ts +30 -0
- package/src/src/tool/types.ts +7 -0
- package/src/src/utils/version-constant.ts +1 -1
package/src/src/mcp/server.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type { ToolExecutionContext } from "../tool/index.js";
|
|
|
5
5
|
import { zodToJsonSchema } from "../tool/schema/index.js";
|
|
6
6
|
import { resourceRegistry } from "../resource/index.js";
|
|
7
7
|
import { promptRegistry } from "../prompt/index.js";
|
|
8
|
-
import type { MCPServerConfig } from "./types.js";
|
|
8
|
+
import type { MCPServerConfig, ToolListEntry } from "./types.js";
|
|
9
9
|
import { createError, toError } from "../errors/veryfront-error.js";
|
|
10
10
|
import { withSpan } from "../observability/tracing/otlp-setup.js";
|
|
11
11
|
import { VERSION } from "../utils/version.js";
|
|
@@ -24,6 +24,30 @@ const PROJECT_ID_PATTERN = /^[a-zA-Z0-9._-]+$/;
|
|
|
24
24
|
|
|
25
25
|
type JSONRPCParams = Record<string, unknown> | unknown[];
|
|
26
26
|
|
|
27
|
+
class JsonRpcError extends Error {
|
|
28
|
+
readonly code: number;
|
|
29
|
+
constructor(code: number, message: string) {
|
|
30
|
+
super(message);
|
|
31
|
+
this.code = code;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function errorCode(error: unknown): number {
|
|
36
|
+
if (typeof error === "object" && error !== null && "code" in error) {
|
|
37
|
+
const code = (error as { code: unknown }).code;
|
|
38
|
+
if (typeof code === "number") return code;
|
|
39
|
+
}
|
|
40
|
+
return -32603;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function errorMessage(error: unknown): string {
|
|
44
|
+
if (error instanceof Error) return error.message;
|
|
45
|
+
if (typeof error === "object" && error !== null && "message" in error) {
|
|
46
|
+
return String((error as { message: unknown }).message);
|
|
47
|
+
}
|
|
48
|
+
return String(error);
|
|
49
|
+
}
|
|
50
|
+
|
|
27
51
|
function toParamsRecord(params: JSONRPCParams | undefined): Record<string, unknown> {
|
|
28
52
|
if (!params || Array.isArray(params)) return {};
|
|
29
53
|
return params;
|
|
@@ -82,6 +106,8 @@ export interface IntegrationLoaderConfig {
|
|
|
82
106
|
apiToken?: string;
|
|
83
107
|
}
|
|
84
108
|
|
|
109
|
+
const MCP_SUPPORTED_VERSIONS = ["2025-11-25", "2024-11-05"];
|
|
110
|
+
|
|
85
111
|
export class MCPServer {
|
|
86
112
|
private config: MCPServerConfig;
|
|
87
113
|
private integrationLoader?: IntegrationLoaderConfig;
|
|
@@ -118,10 +144,7 @@ export class MCPServer {
|
|
|
118
144
|
return {
|
|
119
145
|
jsonrpc: "2.0",
|
|
120
146
|
id: request.id,
|
|
121
|
-
error: {
|
|
122
|
-
code: -32603,
|
|
123
|
-
message: error instanceof Error ? error.message : String(error),
|
|
124
|
-
},
|
|
147
|
+
error: { code: errorCode(error), message: errorMessage(error) },
|
|
125
148
|
};
|
|
126
149
|
}
|
|
127
150
|
},
|
|
@@ -149,6 +172,8 @@ export class MCPServer {
|
|
|
149
172
|
return this.getPrompt(params);
|
|
150
173
|
case "initialize":
|
|
151
174
|
return this.initialize(params);
|
|
175
|
+
case "notifications/initialized":
|
|
176
|
+
return Promise.resolve({});
|
|
152
177
|
default:
|
|
153
178
|
throw toError(
|
|
154
179
|
createError({
|
|
@@ -159,19 +184,33 @@ export class MCPServer {
|
|
|
159
184
|
}
|
|
160
185
|
}
|
|
161
186
|
|
|
162
|
-
private initialize(
|
|
187
|
+
private initialize(params: JSONRPCParams | undefined): Promise<Record<string, unknown>> {
|
|
188
|
+
const p = toParamsRecord(params);
|
|
189
|
+
const requested = typeof p.protocolVersion === "string" ? p.protocolVersion : undefined;
|
|
190
|
+
const negotiated = requested && MCP_SUPPORTED_VERSIONS.includes(requested)
|
|
191
|
+
? requested
|
|
192
|
+
: MCP_SUPPORTED_VERSIONS[0];
|
|
193
|
+
|
|
163
194
|
return Promise.resolve({
|
|
164
|
-
protocolVersion:
|
|
165
|
-
serverInfo: {
|
|
195
|
+
protocolVersion: negotiated,
|
|
196
|
+
serverInfo: {
|
|
197
|
+
name: "veryfront-mcp",
|
|
198
|
+
title: "Veryfront MCP Server",
|
|
199
|
+
version: VERSION,
|
|
200
|
+
description:
|
|
201
|
+
"Veryfront development server tools for real-time errors, route preview, HMR control, and scaffolding",
|
|
202
|
+
},
|
|
166
203
|
capabilities: {
|
|
167
|
-
tools: {},
|
|
168
|
-
resources: { subscribe: true },
|
|
169
|
-
prompts: {},
|
|
204
|
+
tools: { listChanged: true },
|
|
205
|
+
resources: { subscribe: true, listChanged: true },
|
|
206
|
+
prompts: { listChanged: true },
|
|
170
207
|
},
|
|
208
|
+
instructions:
|
|
209
|
+
"Veryfront MCP server provides development tools. Use vf_get_errors to check for code errors, vf_get_logs for server logs, vf_scaffold for code generation, and vf_get_project_context for project structure.",
|
|
171
210
|
});
|
|
172
211
|
}
|
|
173
212
|
|
|
174
|
-
private async listTools(): Promise<{ tools:
|
|
213
|
+
private async listTools(): Promise<{ tools: ToolListEntry[] }> {
|
|
175
214
|
// Sync integration config to API on first tools/list call
|
|
176
215
|
if (this.integrationLoader && !this.integrationsLoaded) {
|
|
177
216
|
try {
|
|
@@ -182,16 +221,19 @@ export class MCPServer {
|
|
|
182
221
|
}
|
|
183
222
|
|
|
184
223
|
const registry = getMCPRegistry();
|
|
185
|
-
const tools:
|
|
224
|
+
const tools: ToolListEntry[] = [];
|
|
186
225
|
|
|
187
226
|
for (const [id, tool] of registry.tools.entries()) {
|
|
188
227
|
if (tool.mcp?.enabled === false) continue;
|
|
189
228
|
|
|
190
|
-
|
|
229
|
+
const entry: ToolListEntry = {
|
|
191
230
|
name: id,
|
|
192
231
|
description: tool.description,
|
|
193
232
|
inputSchema: tool.inputSchemaJson ?? zodToJsonSchema(tool.inputSchema),
|
|
194
|
-
}
|
|
233
|
+
};
|
|
234
|
+
if (tool.mcp?.title) entry.title = tool.mcp.title;
|
|
235
|
+
if (tool.mcp?.annotations) entry.annotations = tool.mcp.annotations;
|
|
236
|
+
tools.push(entry);
|
|
195
237
|
}
|
|
196
238
|
|
|
197
239
|
return { tools };
|
|
@@ -204,29 +246,42 @@ export class MCPServer {
|
|
|
204
246
|
const { name, arguments: args } = toParamsRecord(params);
|
|
205
247
|
|
|
206
248
|
if (!name) {
|
|
207
|
-
throw toError(
|
|
208
|
-
createError({
|
|
209
|
-
type: "agent",
|
|
210
|
-
message: "Tool name is required",
|
|
211
|
-
}),
|
|
212
|
-
);
|
|
249
|
+
throw toError(createError({ type: "agent", message: "Tool name is required" }));
|
|
213
250
|
}
|
|
214
251
|
|
|
215
252
|
const toolName = String(name);
|
|
216
253
|
|
|
254
|
+
const registry = getMCPRegistry();
|
|
255
|
+
const tool = registry.tools.get(toolName);
|
|
256
|
+
if (!tool) {
|
|
257
|
+
throw new JsonRpcError(-32602, `Unknown tool: ${toolName}`);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (tool.inputSchema && typeof tool.inputSchema.parse === "function") {
|
|
261
|
+
try {
|
|
262
|
+
tool.inputSchema.parse(args ?? {});
|
|
263
|
+
} catch (error) {
|
|
264
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
265
|
+
throw new JsonRpcError(-32602, `Invalid arguments for tool ${toolName}: ${message}`);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
217
269
|
return withSpan(
|
|
218
270
|
"mcp.callTool",
|
|
219
271
|
async () => {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
272
|
+
try {
|
|
273
|
+
const result = await executeTool(toolName, args, context);
|
|
274
|
+
return {
|
|
275
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
276
|
+
isError: false,
|
|
277
|
+
};
|
|
278
|
+
} catch (error) {
|
|
279
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
280
|
+
return {
|
|
281
|
+
content: [{ type: "text", text: message }],
|
|
282
|
+
isError: true,
|
|
283
|
+
};
|
|
284
|
+
}
|
|
230
285
|
},
|
|
231
286
|
{ "mcp.tool.name": toolName },
|
|
232
287
|
);
|
|
@@ -353,6 +408,12 @@ export class MCPServer {
|
|
|
353
408
|
return new dntShim.Response(null, { status: 204, headers: this.getCORSHeaders(requestOrigin) });
|
|
354
409
|
}
|
|
355
410
|
|
|
411
|
+
if (requestOrigin && this.config.cors?.enabled && this.config.cors.origins?.length) {
|
|
412
|
+
if (!this.config.cors.origins.includes(requestOrigin)) {
|
|
413
|
+
return createJSONRPCErrorResponse(403, -32600, "Forbidden: Origin not allowed");
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
356
417
|
if (this.config.auth?.type && this.config.auth.type !== "none") {
|
|
357
418
|
const authorized = await this.validateAuth(request);
|
|
358
419
|
if (!authorized) return new dntShim.Response("Unauthorized", { status: 401 });
|
package/src/src/mcp/types.ts
CHANGED
|
@@ -3,6 +3,17 @@ import type { Tool } from "../tool/index.js";
|
|
|
3
3
|
import type { Resource } from "../resource/index.js";
|
|
4
4
|
import type { Prompt } from "../prompt/index.js";
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Behavioral hints for MCP clients (MCP 2025-11-25).
|
|
8
|
+
* Guides auto-approval, confirmation prompts, and caching.
|
|
9
|
+
*/
|
|
10
|
+
export interface ToolAnnotations {
|
|
11
|
+
readOnlyHint?: boolean;
|
|
12
|
+
destructiveHint?: boolean;
|
|
13
|
+
idempotentHint?: boolean;
|
|
14
|
+
openWorldHint?: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
6
17
|
/**
|
|
7
18
|
* Generic MCP tool definition
|
|
8
19
|
*/
|
|
@@ -13,6 +24,19 @@ export interface MCPTool<TInput = any, TOutput = any> {
|
|
|
13
24
|
// deno-lint-ignore no-explicit-any -- ZodType Def/Input params require any for ZodDefault/ZodOptional compatibility
|
|
14
25
|
inputSchema: z.ZodType<TInput, any, any>;
|
|
15
26
|
execute: (input: TInput) => Promise<TOutput>;
|
|
27
|
+
title?: string;
|
|
28
|
+
annotations?: ToolAnnotations;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Wire format for a single tool in a tools/list response.
|
|
33
|
+
*/
|
|
34
|
+
export interface ToolListEntry {
|
|
35
|
+
name: string;
|
|
36
|
+
description: string;
|
|
37
|
+
inputSchema: unknown;
|
|
38
|
+
title?: string;
|
|
39
|
+
annotations?: ToolAnnotations;
|
|
16
40
|
}
|
|
17
41
|
|
|
18
42
|
export interface MCPRegistry {
|
|
@@ -31,6 +31,7 @@ import { BaseHandler } from "../response/base.js";
|
|
|
31
31
|
import type { HandlerContext, HandlerMetadata, HandlerPriority, HandlerResult } from "../types.js";
|
|
32
32
|
import { PRIORITY_MEDIUM_API } from "../../../utils/constants/index.js";
|
|
33
33
|
import { getHostEnv } from "../../../platform/compat/process.js";
|
|
34
|
+
import { serverLogger } from "../../../utils/index.js";
|
|
34
35
|
|
|
35
36
|
export interface AgentStreamHandlerDeps
|
|
36
37
|
extends RuntimeAgentDiscoveryDeps, RuntimeAgentStreamExecutionDeps {
|
|
@@ -42,6 +43,7 @@ const defaultDeps: AgentStreamHandlerDeps = {
|
|
|
42
43
|
sessionManager: agentRunSessionManager,
|
|
43
44
|
resolveRuntimeOwnerInvokeUrl,
|
|
44
45
|
};
|
|
46
|
+
const logger = serverLogger.component("agent-stream-handler");
|
|
45
47
|
|
|
46
48
|
type SourceContextFsWrapper = {
|
|
47
49
|
isMultiProjectMode?: () => boolean;
|
|
@@ -165,6 +167,16 @@ export class AgentStreamHandler extends BaseHandler {
|
|
|
165
167
|
expectedSubject: payload.runId,
|
|
166
168
|
expectedSurface: "studio",
|
|
167
169
|
});
|
|
170
|
+
logger.info("Accepted internal agent stream request", {
|
|
171
|
+
runId: payload.runId,
|
|
172
|
+
threadId: payload.threadId,
|
|
173
|
+
agentId: payload.agentId,
|
|
174
|
+
projectId: ctx.projectId,
|
|
175
|
+
projectSlug: ctx.projectSlug,
|
|
176
|
+
messageCount: payload.messages.length,
|
|
177
|
+
toolCount: payload.tools.length,
|
|
178
|
+
hasAgentSource: Boolean(payload.agentSource),
|
|
179
|
+
});
|
|
168
180
|
|
|
169
181
|
return await this.withAgentSourceContext(
|
|
170
182
|
ctx,
|
|
@@ -174,6 +186,12 @@ export class AgentStreamHandler extends BaseHandler {
|
|
|
174
186
|
|
|
175
187
|
const agent = this.deps.getAgent(payload.agentId);
|
|
176
188
|
if (!agent) {
|
|
189
|
+
logger.warn("Internal agent stream request referenced unknown agent", {
|
|
190
|
+
runId: payload.runId,
|
|
191
|
+
agentId: payload.agentId,
|
|
192
|
+
projectId: ctx.projectId,
|
|
193
|
+
projectSlug: ctx.projectSlug,
|
|
194
|
+
});
|
|
177
195
|
return this.respond(builder.json({ error: "Agent not found" }, 404));
|
|
178
196
|
}
|
|
179
197
|
|
|
@@ -182,6 +200,13 @@ export class AgentStreamHandler extends BaseHandler {
|
|
|
182
200
|
agent as Agent,
|
|
183
201
|
this.deps,
|
|
184
202
|
);
|
|
203
|
+
logger.info("Internal agent stream response created", {
|
|
204
|
+
runId: payload.runId,
|
|
205
|
+
threadId: payload.threadId,
|
|
206
|
+
agentId: payload.agentId,
|
|
207
|
+
projectId: ctx.projectId,
|
|
208
|
+
projectSlug: ctx.projectSlug,
|
|
209
|
+
});
|
|
185
210
|
const runtimeOwnerInvokeUrl = await this.deps.resolveRuntimeOwnerInvokeUrl?.(req) ??
|
|
186
211
|
null;
|
|
187
212
|
const responseWithOwner = runtimeOwnerInvokeUrl
|
|
@@ -224,6 +249,11 @@ export class AgentStreamHandler extends BaseHandler {
|
|
|
224
249
|
projectId: ctx.projectId,
|
|
225
250
|
projectSlug: ctx.projectSlug,
|
|
226
251
|
});
|
|
252
|
+
logger.error("Internal agent stream handler failed", {
|
|
253
|
+
projectId: ctx.projectId,
|
|
254
|
+
projectSlug: ctx.projectSlug,
|
|
255
|
+
error: error instanceof Error ? error.message : String(error),
|
|
256
|
+
});
|
|
227
257
|
return this.respond(builder.json({ error: "Internal agent stream failed" }, 500));
|
|
228
258
|
}
|
|
229
259
|
});
|
package/src/src/tool/types.ts
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
import type { z } from "zod";
|
|
6
6
|
import type { JsonSchema } from "./schema/json-schema.js";
|
|
7
7
|
import type { BlobStorage } from "../workflow/blob/types.js";
|
|
8
|
+
// type-only import — no runtime circular dependency (tool ↔ mcp)
|
|
9
|
+
import type { ToolAnnotations } from "../mcp/types.js";
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* Tool configuration options
|
|
@@ -41,6 +43,11 @@ export interface ToolConfig<TInput = any, TOutput = any> {
|
|
|
41
43
|
|
|
42
44
|
/** Cache policy */
|
|
43
45
|
cachePolicy?: "no-cache" | "cache" | "cache-first";
|
|
46
|
+
|
|
47
|
+
/** Human-readable title for display */
|
|
48
|
+
title?: string;
|
|
49
|
+
/** Behavioral hints for clients (MCP 2025-11-25) */
|
|
50
|
+
annotations?: ToolAnnotations;
|
|
44
51
|
};
|
|
45
52
|
}
|
|
46
53
|
|