Merge branch 'main' into vscode-client-factory

This commit is contained in:
Simon Knott
2025-08-12 10:19:31 +02:00
5 changed files with 105 additions and 56 deletions

View File

@@ -16,14 +16,15 @@
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { ListRootsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
import { BrowserContextFactory } from './browserContextFactory.js';
import { BrowserServerBackend } from './browserServerBackend.js';
import { InProcessTransport } from './mcp/inProcessTransport.js';
import * as mcpServer from './mcp/server.js';
import type { Server } from '@modelcontextprotocol/sdk/server/index.js';
import type { FullConfig } from './config.js';
import type { ClientFactory } from './mcp/proxyBackend.js';
import type { Implementation } from '@modelcontextprotocol/sdk/types.js';
export class InProcessClientFactory implements ClientFactory {
name: string;
@@ -39,10 +40,20 @@ export class InProcessClientFactory implements ClientFactory {
this._config = config;
}
async create(clientVersion: Implementation): Promise<Client> {
const client = new Client(clientVersion);
const server = mcpServer.createServer(new BrowserServerBackend(this._config, this._contextFactory), false);
await client.connect(new InProcessTransport(server));
async create(server: Server): Promise<Client> {
const client = new Client(server.getClientVersion() ?? { name: 'unknown', version: 'unknown' });
const clientCapabilities = server.getClientCapabilities();
if (clientCapabilities)
client.registerCapabilities(clientCapabilities);
if (clientCapabilities?.roots) {
client.setRequestHandler(ListRootsRequestSchema, async () => {
return await server.listRoots();
});
}
const delegate = mcpServer.createServer(new BrowserServerBackend(this._config, this._contextFactory), false);
await client.connect(new InProcessTransport(delegate));
await client.ping();
return client;
}

View File

@@ -23,14 +23,13 @@ import { packageJSON } from '../package.js';
import { logUnhandledError } from '../log.js';
import type { Client } from '@modelcontextprotocol/sdk/client/index.js';
import type { Implementation } from '@modelcontextprotocol/sdk/types.js';
type NonEmptyArray<T> = [T, ...T[]];
export type ClientFactory = {
name: string;
description: string;
create(clientVersion: Implementation, options: any): Promise<Client>;
create(server: Server, options: any): Promise<Client>;
};
export type ClientFactoryList = NonEmptyArray<ClientFactory>;
@@ -43,7 +42,7 @@ export class ProxyBackend implements ServerBackend {
private _currentClient: Client | undefined;
private _contextSwitchTool: Tool<any>;
private _tools: ToolSchema<any>[] = [];
private _server?: Server;
private _server: Server | undefined;
constructor(clientFactories: ClientFactoryList) {
this._clientFactories = clientFactories;
@@ -123,7 +122,7 @@ export class ProxyBackend implements ServerBackend {
private async _setCurrentClient(factory: ClientFactory, options: any) {
await this._currentClient?.close();
this._currentClient = await factory.create(this._server!.getClientVersion()!, options);
this._currentClient = await factory.create(this._server!, options);
const tools = await this._currentClient.listTools();
this._tools = tools.tools.map(tool => ({
name: tool.name,

View File

@@ -76,9 +76,7 @@ export function createServer(backend: ServerBackend, runHeartbeat: boolean): Ser
return { tools: tools.map(tool => ({
name: tool.name,
description: tool.description,
// TODO: we expect inputSchema to be a zod schema, but in the out-of-process case it's already a json schema.
// we should move the "zodToJsonSchema" call into defineTool.
inputSchema: tool.inputSchema.$schema ? tool.inputSchema : zodToJsonSchema(tool.inputSchema),
inputSchema: tool.inputSchema instanceof z.ZodType ? zodToJsonSchema(tool.inputSchema) : tool.inputSchema,
annotations: {
title: tool.title,
readOnlyHint: tool.type === 'readOnly',