or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication.mdclient.mdindex.mdserver-advanced.mdserver-prompts.mdserver-resources.mdserver-tools.mdtransports.mdtypes.md

server-advanced.mddocs/

0

# Server Advanced Features

1

2

Advanced capabilities: sampling (LLM completions), elicitation (user input), dynamic capability management, and low-level protocol access.

3

4

## Sampling (LLM Completions)

5

6

Servers can request LLM completions from clients, enabling tools to use AI capabilities.

7

8

```typescript { .api }

9

async createMessage(

10

params: {

11

messages: SamplingMessage[]; // Messages for the LLM

12

maxTokens?: number; // Maximum tokens to generate

13

modelPreferences?: ModelPreferences; // Model preferences

14

systemPrompt?: string; // System prompt

15

includeContext?: 'none' | 'thisServer' | 'allServers';

16

temperature?: number; // Temperature (0-1)

17

stopSequences?: string[]; // Stop sequences

18

metadata?: Record<string, unknown>; // Request metadata

19

},

20

options?: RequestOptions

21

): Promise<CreateMessageResult>;

22

23

interface SamplingMessage {

24

role: 'user' | 'assistant';

25

content: TextContent | ImageContent | AudioContent;

26

}

27

28

interface ModelPreferences {

29

hints?: ModelHint[]; // Prioritized model hints

30

costPriority?: number; // 0-1, higher = prefer cheaper

31

speedPriority?: number; // 0-1, higher = prefer faster

32

intelligencePriority?: number; // 0-1, higher = prefer smarter

33

}

34

35

interface CreateMessageResult {

36

role: 'assistant';

37

content: TextContent | ImageContent | AudioContent;

38

model: string;

39

stopReason?: 'endTurn' | 'stopSequence' | 'maxTokens';

40

_meta?: Record<string, unknown>;

41

}

42

```

43

44

### Example

45

46

```typescript

47

import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';

48

import { z } from 'zod';

49

50

const server = new McpServer({ name: 'sampling-server', version: '1.0.0' });

51

52

server.registerTool('summarize', {

53

title: 'Summarize Text',

54

description: 'Summarize text using an LLM',

55

inputSchema: { text: z.string().describe('Text to summarize') },

56

outputSchema: { summary: z.string() }

57

}, async ({ text }) => {

58

const response = await server.server.createMessage({

59

messages: [{

60

role: 'user',

61

content: { type: 'text', text: `Please summarize the following text concisely:\n\n${text}` }

62

}],

63

maxTokens: 500,

64

temperature: 0.7

65

});

66

67

const summary = response.content.type === 'text' ? response.content.text : 'Unable to generate summary';

68

const output = { summary };

69

70

return {

71

content: [{ type: 'text', text: JSON.stringify(output) }],

72

structuredContent: output

73

};

74

});

75

```

76

77

## Elicitation (User Input)

78

79

Servers can request structured input from users through forms.

80

81

```typescript { .api }

82

async elicitInput(

83

params: {

84

message: string; // Message to display to user

85

requestedSchema: JSONSchema; // JSON Schema describing requested input

86

},

87

options?: RequestOptions

88

): Promise<ElicitResult>;

89

90

interface ElicitResult {

91

action: 'accept' | 'decline' | 'cancel';

92

content?: Record<string, unknown>; // User-provided content if action is 'accept'

93

_meta?: Record<string, unknown>;

94

}

95

```

96

97

### Examples

98

99

```typescript

100

// User confirmation

101

server.registerTool('delete-file', {

102

title: 'Delete File',

103

description: 'Delete a file with user confirmation',

104

inputSchema: { filePath: z.string() },

105

outputSchema: { deleted: z.boolean() }

106

}, async ({ filePath }) => {

107

const result = await server.server.elicitInput({

108

message: `Are you sure you want to delete ${filePath}?`,

109

requestedSchema: {

110

type: 'object',

111

properties: {

112

confirm: { type: 'boolean', title: 'Confirm deletion', description: 'Check to confirm file deletion' }

113

},

114

required: ['confirm']

115

}

116

});

117

118

let output;

119

if (result.action === 'accept' && result.content?.confirm) {

120

await fs.unlink(filePath);

121

output = { deleted: true };

122

} else {

123

output = { deleted: false };

124

}

125

126

return {

127

content: [{ type: 'text', text: JSON.stringify(output) }],

128

structuredContent: output

129

};

130

});

131

132

// Restaurant booking with alternatives

133

server.registerTool('book-restaurant', {

134

title: 'Book Restaurant',

135

description: 'Book a table at a restaurant',

136

inputSchema: { restaurant: z.string(), date: z.string(), partySize: z.number() }

137

}, async ({ restaurant, date, partySize }) => {

138

const available = await checkAvailability(restaurant, date, partySize);

139

140

if (!available) {

141

const result = await server.server.elicitInput({

142

message: `No tables available at ${restaurant} on ${date}. Would you like to check alternative dates?`,

143

requestedSchema: {

144

type: 'object',

145

properties: {

146

checkAlternatives: { type: 'boolean', title: 'Check alternative dates' },

147

flexibleDates: {

148

type: 'string',

149

title: 'Date flexibility',

150

enum: ['next_day', 'same_week', 'next_week'],

151

enumNames: ['Next day', 'Same week', 'Next week']

152

}

153

},

154

required: ['checkAlternatives']

155

}

156

});

157

158

if (result.action === 'accept' && result.content?.checkAlternatives) {

159

const alternatives = await findAlternatives(restaurant, date, partySize, result.content.flexibleDates);

160

return {

161

content: [{ type: 'text', text: `Alternative dates: ${alternatives.join(', ')}` }],

162

structuredContent: { alternatives }

163

};

164

}

165

}

166

167

await makeBooking(restaurant, date, partySize);

168

return {

169

content: [{ type: 'text', text: 'Booking confirmed' }],

170

structuredContent: { success: true }

171

};

172

});

173

```

174

175

## Dynamic Capability Management

176

177

Tools, resources, and prompts can be controlled at runtime:

178

179

```typescript { .api }

180

interface RegisteredTool {

181

enable(): void; // Make visible in listTools

182

disable(): void; // Hide from listTools

183

update(config: Partial<ToolConfig>): void; // Update configuration

184

remove(): void; // Remove entirely

185

}

186

```

187

188

### Example

189

190

```typescript

191

// Register tools with different access levels

192

const readTool = server.registerTool('read-data', readConfig, readCallback);

193

const writeTool = server.registerTool('write-data', writeConfig, writeCallback);

194

const adminTool = server.registerTool('admin-action', adminConfig, adminCallback);

195

196

// Initially, only read access

197

writeTool.disable();

198

adminTool.disable();

199

200

// After authentication, enable based on role

201

function updatePermissions(userRole: string) {

202

if (userRole === 'editor') {

203

writeTool.enable();

204

} else if (userRole === 'admin') {

205

writeTool.enable();

206

adminTool.enable();

207

}

208

server.sendToolListChanged();

209

}

210

211

// Dynamic tool update

212

readTool.update({ description: `Read data (authenticated as ${username})` });

213

```

214

215

## Notification Debouncing

216

217

Reduce network traffic by coalescing rapid notifications:

218

219

```typescript

220

const server = new McpServer(

221

{ name: 'efficient-server', version: '1.0.0' },

222

{

223

debouncedNotificationMethods: [

224

'notifications/tools/list_changed',

225

'notifications/resources/list_changed',

226

'notifications/prompts/list_changed'

227

]

228

}

229

);

230

231

// Bulk updates send only one notification per type

232

for (let i = 0; i < 100; i++) {

233

server.registerTool(`tool${i}`, config, callback).disable();

234

}

235

// Only one notifications/tools/list_changed sent

236

```

237

238

## Low-Level Server Access

239

240

```typescript { .api }

241

const mcpServer = new McpServer({ name: 'my-server', version: '1.0.0' });

242

const lowLevelServer = mcpServer.server; // Access underlying Server instance

243

244

// Set custom request handlers

245

lowLevelServer.setRequestHandler(CustomRequestSchema, async (request, extra) => {

246

return customResult;

247

});

248

249

// Set custom notification handlers

250

lowLevelServer.setNotificationHandler(CustomNotificationSchema, async (notification) => {

251

// Handle notification

252

});

253

254

// Send custom requests to client

255

const result = await lowLevelServer.request({ method: 'custom/method', params: {} }, CustomResultSchema);

256

257

// Send custom notifications to client

258

await lowLevelServer.notification({ method: 'custom/notification', params: {} });

259

```

260

261

## Protocol Base Class

262

263

```typescript { .api }

264

import { Protocol, ProtocolOptions, RequestOptions, NotificationOptions } from '@modelcontextprotocol/sdk/shared/protocol.js';

265

266

abstract class Protocol<RequestT, NotificationT, ResultT> {

267

protected transport?: Transport;

268

269

setRequestHandler<T extends ZodType<object>>(schema: T, handler: (request: z.infer<T>, extra: RequestHandlerExtra) => Promise<Result> | Result): void;

270

setNotificationHandler<T extends ZodType<object>>(schema: T, handler: (notification: z.infer<T>) => Promise<void> | void): void;

271

request<U extends ZodType<object>>(request: RequestT, resultSchema: U, options?: RequestOptions): Promise<z.infer<U>>;

272

notification(notification: NotificationT, options?: NotificationOptions): Promise<void>;

273

close(): Promise<void>;

274

connect(transport: Transport): Promise<void>;

275

}

276

277

interface ProtocolOptions {

278

enforceStrictCapabilities?: boolean; // Default: true

279

debouncedNotificationMethods?: string[];

280

}

281

```

282

283

## Client Information

284

285

```typescript { .api }

286

server.getClientCapabilities(): ClientCapabilities | undefined;

287

server.getClientVersion(): Implementation | undefined;

288

```

289

290

## Logging

291

292

```typescript { .api }

293

async sendLoggingMessage(

294

params: {

295

level: LoggingLevel;

296

logger?: string;

297

data: unknown;

298

},

299

sessionId?: string

300

): Promise<void>;

301

302

type LoggingLevel = 'debug' | 'info' | 'notice' | 'warning' | 'error' | 'critical' | 'alert' | 'emergency';

303

```

304

305

### Example

306

307

```typescript

308

await server.sendLoggingMessage({

309

level: 'info',

310

logger: 'my-tool',

311

data: 'Operation completed successfully'

312

});

313

314

await server.sendLoggingMessage({

315

level: 'error',

316

logger: 'database',

317

data: { error: 'Connection failed', code: 'ECONNREFUSED' }

318

});

319

```

320

321

## Roots Management

322

323

```typescript { .api }

324

async listRoots(params?: Record<string, unknown>, options?: RequestOptions): Promise<ListRootsResult>;

325

326

interface ListRootsResult {

327

roots: Root[];

328

_meta?: Record<string, unknown>;

329

}

330

331

interface Root {

332

uri: string;

333

name: string;

334

}

335

```

336

337

## Connection Management

338

339

```typescript { .api }

340

isConnected(): boolean;

341

async close(): Promise<void>;

342

```

343

344

## Lifecycle Callbacks

345

346

```typescript

347

server.server.oninitialized = () => { console.log('Client initialized'); };

348

server.server.onclose = () => { console.log('Connection closed'); };

349

server.server.onerror = (error) => { console.error('Server error:', error); };

350

```

351

352

## Types Reference

353

354

```typescript { .api }

355

interface RequestHandlerExtra {

356

request: <U>(request: Request, resultSchema: U, options?: RequestOptions) => Promise<Result>;

357

notification: (notification: Notification, options?: NotificationOptions) => Promise<void>;

358

sessionId?: string;

359

requestInfo?: RequestInfo;

360

signal: AbortSignal;

361

}

362

363

interface RequestOptions {

364

timeout?: number;

365

onprogress?: (progress: Progress) => void;

366

signal?: AbortSignal;

367

}

368

369

interface NotificationOptions {

370

priority?: number;

371

}

372

```

373