Skip to content
4 changes: 2 additions & 2 deletions packages/core/src/types/spec.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,7 @@ export interface ClientCapabilities {
* @example Extensions — UI extension with MIME type support
* {@includeCode ./examples/ClientCapabilities/extensions-ui-mime-types.json}
*/
extensions?: { [key: string]: object };
extensions?: { [key: string]: JSONObject };
}

/**
Expand Down Expand Up @@ -703,7 +703,7 @@ export interface ServerCapabilities {
* @example Extensions — UI extension support
* {@includeCode ./examples/ServerCapabilities/extensions-ui.json}
*/
extensions?: { [key: string]: object };
extensions?: { [key: string]: JSONObject };
}

/**
Expand Down
12 changes: 10 additions & 2 deletions packages/core/src/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,11 @@ export const ClientCapabilitiesSchema = z.object({
/**
* Present if the client supports task creation.
*/
tasks: ClientTasksCapabilitySchema.optional()
tasks: ClientTasksCapabilitySchema.optional(),
/**
* Extensions that the client supports. Keys are extension identifiers (vendor-prefix/extension-name).
*/
extensions: z.record(z.string(), JSONObjectSchema).optional()
});

export const InitializeRequestParamsSchema = BaseRequestParamsSchema.extend({
Expand Down Expand Up @@ -635,7 +639,11 @@ export const ServerCapabilitiesSchema = z.object({
/**
* Present if the server supports task creation.
*/
tasks: ServerTasksCapabilitySchema.optional()
tasks: ServerTasksCapabilitySchema.optional(),
/**
* Extensions that the server supports. Keys are extension identifiers (vendor-prefix/extension-name).
*/
extensions: z.record(z.string(), JSONObjectSchema).optional()
});

/**
Expand Down
54 changes: 54 additions & 0 deletions test/integration/test/server/mcp.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,60 @@ describe('Zod v4', () => {
message: 'Completed step 3 of 3'
});
});

/***
* Test: Extensions capability registration
*/
test('should register and advertise server extensions capability', async () => {
const mcpServer = new McpServer({
name: 'test server',
version: '1.0'
});
const client = new Client({
name: 'test client',
version: '1.0'
});

mcpServer.server.registerCapabilities({
extensions: {
'io.modelcontextprotocol/test-extension': { listChanged: true }
}
});

const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
await Promise.all([client.connect(clientTransport), mcpServer.connect(serverTransport)]);

const capabilities = client.getServerCapabilities();
expect(capabilities?.extensions).toBeDefined();
expect(capabilities?.extensions?.['io.modelcontextprotocol/test-extension']).toEqual({ listChanged: true });
});

test('should advertise client extensions capability to server', async () => {
const mcpServer = new McpServer({
name: 'test server',
version: '1.0'
});
const client = new Client(
{
name: 'test client',
version: '1.0'
},
{
capabilities: {
extensions: {
'io.modelcontextprotocol/test-extension': { streaming: true }
}
}
}
);

const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
await Promise.all([client.connect(clientTransport), mcpServer.connect(serverTransport)]);

const capabilities = mcpServer.server.getClientCapabilities();
expect(capabilities?.extensions).toBeDefined();
expect(capabilities?.extensions?.['io.modelcontextprotocol/test-extension']).toEqual({ streaming: true });
});
});

describe('ResourceTemplate', () => {
Expand Down
Loading