Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/api-reference/veryfront/agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -922,7 +922,7 @@ Input delivered to a hosted agent-service detached execution callback.
| `prepareConversationRunExternalEvents` | Prepare conversation run external events. | [source](https://github.com/veryfront/veryfront-code/blob/main/src/agent/conversation/run-event-preparation.ts#L78) |
| `prepareConversationRunStreamEvents` | Prepare conversation run stream events. | [source](https://github.com/veryfront/veryfront-code/blob/main/src/agent/conversation/run-event-preparation.ts#L59) |
| `prepareDefaultHostedChildForkRuntimeTools` | Prepare default hosted child fork runtime tools. | [source](https://github.com/veryfront/veryfront-code/blob/main/src/agent/hosted/child-requested-tools.ts#L312) |
| `prepareDefaultHostedChildForkSandboxToolSources` | Prepare default hosted child fork sandbox tool sources. | [source](https://github.com/veryfront/veryfront-code/blob/main/src/agent/hosted/child-fork-tool-sources.ts#L196) |
| `prepareDefaultHostedChildForkSandboxToolSources` | Prepare default hosted child fork sandbox tool sources. | [source](https://github.com/veryfront/veryfront-code/blob/main/src/agent/hosted/child-fork-tool-sources.ts#L197) |
| `prepareDefaultHostedChildForkToolAssembly` | Prepare default hosted child fork tool assembly. | [source](https://github.com/veryfront/veryfront-code/blob/main/src/agent/hosted/child-requested-tools.ts#L366) |
| `prepareDefaultHostedChildForkToolSources` | Prepare default hosted child fork tool sources. | [source](https://github.com/veryfront/veryfront-code/blob/main/src/agent/hosted/child-fork-tool-sources.ts#L88) |
| `prepareHostedChatExecution` | Prepare hosted chat execution. | [source](https://github.com/veryfront/veryfront-code/blob/main/src/agent/hosted/chat-preparation.ts#L482) |
Expand Down
6 changes: 3 additions & 3 deletions docs/api-reference/veryfront/tool.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ Create a typed tool definition.
| ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| `createContext7ToolSource` | Create context7 tool source. | [source](https://github.com/veryfront/veryfront-code/blob/main/src/tool/context7.ts#L28) |
| `createProjectScopedRemoteToolCatalog` | Create project scoped remote tool catalog. | [source](https://github.com/veryfront/veryfront-code/blob/main/src/tool/project-scoped-remote-tools.ts#L348) |
| `createRemoteMCPToolSource` | Create a remote MCP source with the framework's guarded outbound transport. | [source](https://github.com/veryfront/veryfront-code/blob/main/src/tool/remote-mcp.ts#L970) |
| `createRemoteMCPToolSourceFactoryWithTransport` | Create a remote MCP source factory with narrowly scoped host transport. | [source](https://github.com/veryfront/veryfront-code/blob/main/src/tool/remote-mcp.ts#L1002) |
| `createRemoteMCPToolSource` | Create a remote MCP source with the framework's guarded outbound transport. | [source](https://github.com/veryfront/veryfront-code/blob/main/src/tool/remote-mcp.ts#L983) |
| `createRemoteMCPToolSourceFactoryWithTransport` | Create a remote MCP source factory with narrowly scoped host transport. | [source](https://github.com/veryfront/veryfront-code/blob/main/src/tool/remote-mcp.ts#L1038) |
| `createSleepTool` | Create sleep tool. | [source](https://github.com/veryfront/veryfront-code/blob/main/src/tool/sleep.ts#L54) |
| `createToolsFromHostDefinitions` | Create tools from host definitions. | [source](https://github.com/veryfront/veryfront-code/blob/main/src/tool/host-tools.ts#L96) |
| `createToolsFromRemoteDefinitions` | Create tools from remote definitions. | [source](https://github.com/veryfront/veryfront-code/blob/main/src/tool/remote-source-tools.ts#L29) |
Expand Down Expand Up @@ -170,7 +170,7 @@ Create a typed tool definition.
| `ProjectScopedRemoteToolExecutionInput` | Input payload for project scoped remote tool execution. | [source](https://github.com/veryfront/veryfront-code/blob/main/src/tool/project-scoped-remote-tools.ts#L38) |
| `ProjectScopedRemoteToolOptions` | Options accepted by project scoped remote tool. | [source](https://github.com/veryfront/veryfront-code/blob/main/src/tool/project-scoped-remote-tools.ts#L6) |
| `RemoteMCPToolSourceConfig` | Configuration used by remote MCP tool source. | [source](https://github.com/veryfront/veryfront-code/blob/main/src/tool/remote-mcp.ts#L52) |
| `RemoteMCPToolSourceTransportOptions` | Deployment-owned transport policy for exact, immutable MCP endpoints. | [source](https://github.com/veryfront/veryfront-code/blob/main/src/tool/remote-mcp.ts#L977) |
| `RemoteMCPToolSourceTransportOptions` | Deployment-owned transport policy for trusted MCP endpoint roots. | [source](https://github.com/veryfront/veryfront-code/blob/main/src/tool/remote-mcp.ts#L990) |
| `RemoteToolMaterializationOptions` | Options accepted by remote tool materialization. | [source](https://github.com/veryfront/veryfront-code/blob/main/src/tool/remote-source-tools.ts#L8) |
| `RemoteToolSource` | Remote tool source loaded dynamically at runtime. Hosts can provide these to expose tools from remote MCP-compatible systems without registering those tools globally inside the framework. | [source](https://github.com/veryfront/veryfront-code/blob/main/src/tool/types.ts#L231) |
| `SleepToolInput` | Input payload for sleep tool. | [source](https://github.com/veryfront/veryfront-code/blob/main/src/tool/sleep.ts#L45) |
Expand Down
18 changes: 15 additions & 3 deletions src/agent/hosted/child-fork-tool-sources.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,14 +132,15 @@ Deno.test("prepareDefaultHostedChildForkToolSources loads API, live Studio, and
const fixtures = createRemoteSourceFixtures();
const switchedProjectIds: string[] = [];
const switchedProjects: Array<{ projectId: string; projectSlug?: string }> = [];
let activeProjectId = "project-1";

const result = await prepareDefaultHostedChildForkToolSources({
authToken: "token-1",
apiMcpUrl: "https://api.example/mcp",
mcpServers: [{ kind: "veryfront-api" }, { kind: "veryfront-studio" }],
studioMcpUrl: "https://studio.example/mcp",
clientProfile: trustedStudioProfile,
getProjectId: () => "project-1",
getProjectId: () => activeProjectId,
conversationId: "conversation-1",
globalTools: {
sleep: {
Expand All @@ -148,6 +149,7 @@ Deno.test("prepareDefaultHostedChildForkToolSources loads API, live Studio, and
},
},
onConfirmedStudioProjectSwitch: (projectId, confirmedProject) => {
activeProjectId = projectId;
switchedProjectIds.push(projectId);
if (confirmedProject) {
switchedProjects.push(confirmedProject);
Expand All @@ -163,9 +165,14 @@ Deno.test("prepareDefaultHostedChildForkToolSources loads API, live Studio, and

assertEquals(Object.keys(result.forkTools), ["sleep", "studio_open_project", "update_file"]);
assertEquals(
fixtures.createdConfigs.map((config) => [config.id, config.endpoint]),
await Promise.all(
fixtures.createdConfigs.map(async (config) => [
config.id,
typeof config.endpoint === "function" ? await config.endpoint() : config.endpoint,
]),
),
[
["veryfront-mcp-fork", "https://api.example/mcp"],
["veryfront-mcp-fork", "https://api.example/projects/project-1/mcp"],
["studio-mcp-live-tools", "https://studio.example/mcp"],
],
);
Expand All @@ -174,6 +181,11 @@ Deno.test("prepareDefaultHostedChildForkToolSources loads API, live Studio, and

assertEquals(switchedProjectIds, ["project-2"]);
assertEquals(switchedProjects, [{ projectId: "project-2", projectSlug: "project-two" }]);
const apiConfig = fixtures.createdConfigs.find((config) => config.id === "veryfront-mcp-fork");
assertEquals(
typeof apiConfig?.endpoint === "function" ? await apiConfig.endpoint() : apiConfig?.endpoint,
"https://api.example/projects/project-2/mcp",
);
assertEquals(fixtures.executeCalls, [
{
sourceId: "veryfront-mcp-fork",
Expand Down
1 change: 1 addition & 0 deletions src/agent/hosted/child-fork-tool-sources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ export async function prepareDefaultHostedChildForkToolSources(
server,
authToken: input.authToken,
apiMcpUrl: input.apiMcpUrl,
getProjectId: input.getProjectId,
defaultSourceId: "veryfront-mcp-fork",
});
if (!remoteConfig) {
Expand Down
32 changes: 22 additions & 10 deletions src/agent/hosted/project-remote-tool-source.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@ async function resolveTestHeaders(
return typeof headers === "function" ? await headers(context) : headers;
}

async function resolveTestEndpoint(
endpoint: RemoteMCPToolSourceConfig["endpoint"],
): Promise<string> {
return typeof endpoint === "function" ? await endpoint() : endpoint;
}

Deno.test("hosted remote tool sources do not carry legacy end-user identity plumbing", async () => {
const forbidden = [
["get", "End", "User", "Id"].join(""),
Expand Down Expand Up @@ -673,8 +679,8 @@ Deno.test("createHostedProjectRemoteToolSources defaults to first-party MCP serv
});

assertEquals(sources.map((source) => source.id), ["veryfront-mcp", "studio-mcp"]);
assertEquals(configs.map((config) => config.endpoint), [
"https://api.example/mcp",
assertEquals(await Promise.all(configs.map((config) => resolveTestEndpoint(config.endpoint))), [
"https://api.example/projects/project-1/mcp",
"https://studio.example/mcp",
]);
});
Expand Down Expand Up @@ -790,8 +796,8 @@ Deno.test("createHostedProjectRemoteToolSources builds API and explicit gated St
});

assertEquals(sources.map((source) => source.id), ["veryfront-mcp", "studio-mcp"]);
assertEquals(configs.map((config) => config.endpoint), [
"https://api.example/mcp",
assertEquals(await Promise.all(configs.map((config) => resolveTestEndpoint(config.endpoint))), [
"https://api.example/projects/project-1/mcp",
"https://studio.example/mcp",
]);
assertEquals(await resolveTestHeaders(configs[0]?.headers), {
Expand All @@ -802,6 +808,10 @@ Deno.test("createHostedProjectRemoteToolSources builds API and explicit gated St
});

activeProjectId = "project-2";
assertEquals(
await resolveTestEndpoint(configs[0]?.endpoint ?? ""),
"https://api.example/projects/project-2/mcp",
);
assertEquals(await resolveTestHeaders(configs[1]?.headers), {
Authorization: "Bearer token-1",
"x-conversation-id": "conversation-1",
Expand Down Expand Up @@ -885,8 +895,8 @@ Deno.test("createHostedProjectRemoteToolSources infers Studio MCP from allowed S
});

assertEquals(sources.map((source) => source.id), ["veryfront-mcp", "studio-mcp"]);
assertEquals(configs.map((config) => config.endpoint), [
"https://api.example/mcp",
assertEquals(await Promise.all(configs.map((config) => resolveTestEndpoint(config.endpoint))), [
"https://api.example/projects/project-1/mcp",
"https://studio.example/mcp",
]);
assertEquals(
Expand All @@ -895,7 +905,7 @@ Deno.test("createHostedProjectRemoteToolSources infers Studio MCP from allowed S
);
});

Deno.test("createHostedProjectRemoteToolSources does not infer Studio when explicit API-only MCP is set", () => {
it("does not infer Studio when explicit API-only MCP is set", async () => {
const configs: RemoteMCPToolSourceConfig[] = [];
const sources = createHostedProjectRemoteToolSources({
authToken: "token-1",
Expand All @@ -920,7 +930,9 @@ Deno.test("createHostedProjectRemoteToolSources does not infer Studio when expli
});

assertEquals(sources.map((source) => source.id), ["veryfront-mcp"]);
assertEquals(configs.map((config) => config.endpoint), ["https://api.example/mcp"]);
assertEquals(await Promise.all(configs.map((config) => resolveTestEndpoint(config.endpoint))), [
"https://api.example/projects/project-1/mcp",
]);
});

Deno.test("createHostedProjectRemoteToolSources preserves an explicit MCP opt-out", () => {
Expand Down Expand Up @@ -1027,8 +1039,8 @@ Deno.test("createHostedProjectRemoteToolSources builds explicit MCP server lists
});

assertEquals(sources.map((source) => source.id), ["veryfront-mcp", "studio-mcp", "linear"]);
assertEquals(configs.map((config) => config.endpoint), [
"https://api.example/mcp",
assertEquals(await Promise.all(configs.map((config) => resolveTestEndpoint(config.endpoint))), [
"https://api.example/projects/project-1/mcp",
"https://studio.example/mcp",
"https://linear.example/mcp",
]);
Expand Down
Loading