or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

auth.mdcli.mdclient.mdfastmcp-server.mdindex.mdlowlevel-server.mdtransport.mdtypes.md

lowlevel-server.mddocs/

0

# Low-Level Server Framework

1

2

Low-level server implementation providing full control over MCP protocol handling. The Server class offers decorator-based request handlers, custom lifecycle management, and fine-grained control over protocol capabilities and session management.

3

4

## Capabilities

5

6

### Server Class

7

8

Core server class for implementing MCP protocol handlers with full control over request processing and capabilities.

9

10

```python { .api }

11

class Server:

12

def __init__(

13

self,

14

name: str,

15

version: str | None = None,

16

instructions: str | None = None,

17

lifespan: Callable = default_lifespan,

18

):

19

"""

20

Initialize a low-level MCP server.

21

22

Parameters:

23

- name: Server name for identification

24

- version: Server version string

25

- instructions: Server instructions/description

26

- lifespan: Server lifespan management function

27

"""

28

29

def list_tools(self) -> Callable:

30

"""

31

Decorator for tool listing handler.

32

33

Returns:

34

Decorator function that expects handler returning list[Tool]

35

"""

36

37

def call_tool(self) -> Callable:

38

"""

39

Decorator for tool execution handler.

40

41

Returns:

42

Decorator function that expects handler with (name: str, arguments: dict) -> list[ContentBlock]

43

"""

44

45

def list_resources(self) -> Callable:

46

"""

47

Decorator for resource listing handler.

48

49

Returns:

50

Decorator function that expects handler returning list[Resource]

51

"""

52

53

def read_resource(self) -> Callable:

54

"""

55

Decorator for resource reading handler.

56

57

Returns:

58

Decorator function that expects handler with (uri: AnyUrl) -> list[ContentBlock]

59

"""

60

61

def subscribe_resource(self) -> Callable:

62

"""

63

Decorator for resource subscription handler.

64

65

Returns:

66

Decorator function that expects handler with (uri: AnyUrl) -> None

67

"""

68

69

def unsubscribe_resource(self) -> Callable:

70

"""

71

Decorator for resource unsubscription handler.

72

73

Returns:

74

Decorator function that expects handler with (uri: AnyUrl) -> None

75

"""

76

77

def list_prompts(self) -> Callable:

78

"""

79

Decorator for prompt listing handler.

80

81

Returns:

82

Decorator function that expects handler returning list[Prompt]

83

"""

84

85

def get_prompt(self) -> Callable:

86

"""

87

Decorator for prompt retrieval handler.

88

89

Returns:

90

Decorator function that expects handler with (name: str, arguments: dict) -> GetPromptResult

91

"""

92

93

def set_logging_level(self) -> Callable:

94

"""

95

Decorator for logging level setting handler.

96

97

Returns:

98

Decorator function that expects handler with (level: LoggingLevel) -> None

99

"""

100

101

def completion(self) -> Callable:

102

"""

103

Decorator for completion handler.

104

105

Returns:

106

Decorator function that expects handler with completion request -> list[Completion]

107

"""

108

109

async def run(

110

self,

111

read_stream: MemoryObjectReceiveStream,

112

write_stream: MemoryObjectSendStream,

113

options: InitializationOptions

114

) -> None:

115

"""

116

Run the server with provided streams and options.

117

118

Parameters:

119

- read_stream: Stream for receiving client messages

120

- write_stream: Stream for sending responses to client

121

- options: Server initialization options

122

"""

123

124

async def create_initialization_options(self) -> InitializationOptions:

125

"""

126

Create initialization options for the server.

127

128

Returns:

129

InitializationOptions with server capabilities

130

"""

131

```

132

133

### Configuration Classes

134

135

Configuration and options classes for server initialization and capabilities.

136

137

```python { .api }

138

class InitializationOptions:

139

def __init__(

140

self,

141

server_name: str,

142

server_version: str,

143

capabilities: ServerCapabilities,

144

instructions: str | None = None,

145

):

146

"""

147

Server initialization options.

148

149

Parameters:

150

- server_name: Name of the server

151

- server_version: Version of the server

152

- capabilities: Server capabilities declaration

153

- instructions: Server instructions/description

154

"""

155

156

class NotificationOptions:

157

def __init__(

158

self,

159

tools_changed: bool = True,

160

resources_changed: bool = True,

161

prompts_changed: bool = True,

162

logging: bool = True,

163

progress: bool = True,

164

):

165

"""

166

Notification capability options.

167

168

Parameters:

169

- tools_changed: Enable tool change notifications

170

- resources_changed: Enable resource change notifications

171

- prompts_changed: Enable prompt change notifications

172

- logging: Enable logging notifications

173

- progress: Enable progress notifications

174

"""

175

```

176

177

### Context and Session Access

178

179

Low-level context access for request handling and session management.

180

181

```python { .api }

182

def request_ctx() -> RequestContext:

183

"""

184

Get the current request context.

185

186

Returns:

187

RequestContext for the current request

188

"""

189

190

class RequestContext:

191

@property

192

def request_id(self) -> str:

193

"""Current request identifier."""

194

195

@property

196

def session(self) -> ServerSession:

197

"""Current server session."""

198

199

@property

200

def client_info(self) -> Implementation:

201

"""Client implementation information."""

202

203

@property

204

def server_info(self) -> Implementation:

205

"""Server implementation information."""

206

207

async def send_notification(

208

self,

209

method: str,

210

params: dict[str, Any] | None = None

211

) -> None:

212

"""

213

Send notification to client.

214

215

Parameters:

216

- method: Notification method name

217

- params: Notification parameters

218

"""

219

220

async def send_progress_notification(

221

self,

222

progress_token: ProgressToken,

223

progress: float,

224

total: float | None = None

225

) -> None:

226

"""

227

Send progress notification to client.

228

229

Parameters:

230

- progress_token: Progress tracking token

231

- progress: Current progress value

232

- total: Total expected value

233

"""

234

235

async def send_logging_message(

236

self,

237

level: LoggingLevel,

238

message: str,

239

logger: str | None = None

240

) -> None:

241

"""

242

Send log message to client.

243

244

Parameters:

245

- level: Log level

246

- message: Log message

247

- logger: Logger name

248

"""

249

```

250

251

## Usage Examples

252

253

### Basic Low-Level Server

254

255

```python

256

from mcp.server import Server

257

from mcp import Tool, Resource, TextContent

258

import asyncio

259

260

# Create server instance

261

server = Server("basic-server", version="1.0.0")

262

263

# Tool management

264

available_tools = [

265

Tool(

266

name="echo",

267

description="Echo the input message",

268

inputSchema={

269

"type": "object",

270

"properties": {

271

"message": {"type": "string"}

272

},

273

"required": ["message"]

274

}

275

)

276

]

277

278

@server.list_tools()

279

async def list_tools():

280

"""Return list of available tools."""

281

return available_tools

282

283

@server.call_tool()

284

async def call_tool(name: str, arguments: dict):

285

"""Handle tool execution."""

286

if name == "echo":

287

message = arguments.get("message", "")

288

return [TextContent(type="text", text=f"Echo: {message}")]

289

else:

290

raise ValueError(f"Unknown tool: {name}")

291

292

# Resource management

293

available_resources = [

294

Resource(

295

uri="memory://stats",

296

name="Server Statistics",

297

description="Current server statistics"

298

)

299

]

300

301

@server.list_resources()

302

async def list_resources():

303

"""Return list of available resources."""

304

return available_resources

305

306

@server.read_resource()

307

async def read_resource(uri):

308

"""Handle resource reading."""

309

if str(uri) == "memory://stats":

310

stats = {

311

"uptime": "1 hour",

312

"requests": 42,

313

"tools_called": 12

314

}

315

content = "\n".join(f"{k}: {v}" for k, v in stats.items())

316

return [TextContent(type="text", text=content)]

317

else:

318

raise ValueError(f"Unknown resource: {uri}")

319

320

# Run server with stdio transport

321

async def main():

322

from mcp.server import stdio_server

323

from mcp.server.models import InitializationOptions

324

from mcp import ServerCapabilities, ToolsCapability, ResourcesCapability

325

326

# Create initialization options

327

capabilities = ServerCapabilities(

328

tools=ToolsCapability(listChanged=True),

329

resources=ResourcesCapability(listChanged=True, subscribe=True)

330

)

331

332

options = InitializationOptions(

333

server_name="basic-server",

334

server_version="1.0.0",

335

capabilities=capabilities

336

)

337

338

async with stdio_server() as (read, write):

339

await server.run(read, write, options)

340

341

if __name__ == "__main__":

342

asyncio.run(main())

343

```

344

345

### Server with Custom Capabilities

346

347

```python

348

from mcp.server import Server, request_ctx

349

from mcp import *

350

import asyncio

351

352

server = Server("advanced-server")

353

354

# Custom completion handler

355

@server.completion()

356

async def handle_completion(request):

357

"""Handle completion requests for resources and prompts."""

358

ctx = request_ctx()

359

360

if request.ref.type == "resource":

361

# Complete resource URIs

362

if request.ref.uri.startswith("file://"):

363

# Return file path completions

364

return [

365

Completion(

366

values=["file:///tmp/example.txt", "file:///home/user/doc.md"],

367

total=2

368

)

369

]

370

371

return [Completion(values=[], total=0)]

372

373

# Custom logging level handler

374

@server.set_logging_level()

375

async def set_logging_level(level):

376

"""Handle logging level changes."""

377

ctx = request_ctx()

378

print(f"Client {ctx.client_info.name} set logging level to {level}")

379

380

# Send confirmation

381

await ctx.send_logging_message(

382

LoggingLevel.INFO,

383

f"Logging level set to {level}"

384

)

385

386

# Prompt with arguments

387

prompts = [

388

Prompt(

389

name="code_review",

390

description="Generate code review checklist",

391

arguments=[

392

PromptArgument(

393

name="language",

394

description="Programming language",

395

required=True

396

),

397

PromptArgument(

398

name="complexity",

399

description="Code complexity level",

400

required=False

401

)

402

]

403

)

404

]

405

406

@server.list_prompts()

407

async def list_prompts():

408

"""Return available prompts."""

409

return prompts

410

411

@server.get_prompt()

412

async def get_prompt(name: str, arguments: dict):

413

"""Handle prompt generation."""

414

if name == "code_review":

415

language = arguments.get("language", "Python")

416

complexity = arguments.get("complexity", "medium")

417

418

prompt_text = f"""Code Review Checklist for {language} ({complexity} complexity):

419

420

1. Code Style and Formatting

421

- Consistent indentation and spacing

422

- Meaningful variable and function names

423

- Appropriate comments and documentation

424

425

2. Logic and Functionality

426

- Code achieves intended purpose

427

- Edge cases are handled

428

- Error handling is appropriate

429

430

3. Performance Considerations

431

- Efficient algorithms and data structures

432

- Resource usage optimization

433

- Scalability considerations

434

435

4. Security Review

436

- Input validation

437

- Authentication and authorization

438

- Data sanitization

439

"""

440

441

return GetPromptResult(

442

description=f"Code review checklist for {language}",

443

messages=[

444

PromptMessage(

445

role=Role.user,

446

content=TextContent(type="text", text=prompt_text)

447

)

448

]

449

)

450

else:

451

raise ValueError(f"Unknown prompt: {name}")

452

453

# Resource subscription handling

454

@server.subscribe_resource()

455

async def subscribe_resource(uri):

456

"""Handle resource subscription."""

457

ctx = request_ctx()

458

print(f"Client subscribed to resource: {uri}")

459

460

# Send initial notification

461

await ctx.send_notification(

462

"notifications/resources/updated",

463

{"uri": str(uri), "reason": "subscribed"}

464

)

465

466

@server.unsubscribe_resource()

467

async def unsubscribe_resource(uri):

468

"""Handle resource unsubscription."""

469

ctx = request_ctx()

470

print(f"Client unsubscribed from resource: {uri}")

471

472

async def main():

473

from mcp.server import stdio_server

474

475

options = await server.create_initialization_options()

476

477

async with stdio_server() as (read, write):

478

await server.run(read, write, options)

479

480

if __name__ == "__main__":

481

asyncio.run(main())

482

```

483

484

### Server with Progress Tracking

485

486

```python

487

from mcp.server import Server, request_ctx

488

from mcp import TextContent

489

import asyncio

490

491

server = Server("progress-server")

492

493

@server.call_tool()

494

async def call_tool(name: str, arguments: dict):

495

"""Handle tool calls with progress tracking."""

496

ctx = request_ctx()

497

498

if name == "process_data":

499

items = arguments.get("items", [])

500

total = len(items)

501

502

results = []

503

for i, item in enumerate(items):

504

# Send progress update

505

await ctx.send_progress_notification(

506

progress_token=ctx.request_id,

507

progress=i,

508

total=total

509

)

510

511

# Simulate processing

512

await asyncio.sleep(0.1)

513

results.append(f"Processed: {item}")

514

515

# Send final progress

516

await ctx.send_progress_notification(

517

progress_token=ctx.request_id,

518

progress=total,

519

total=total

520

)

521

522

return [TextContent(

523

type="text",

524

text=f"Completed processing {total} items: {results}"

525

)]

526

527

return [TextContent(type="text", text="Unknown tool")]

528

529

@server.list_tools()

530

async def list_tools():

531

"""Return tools that support progress tracking."""

532

return [

533

Tool(

534

name="process_data",

535

description="Process data items with progress tracking",

536

inputSchema={

537

"type": "object",

538

"properties": {

539

"items": {

540

"type": "array",

541

"items": {"type": "string"}

542

}

543

},

544

"required": ["items"]

545

}

546

)

547

]

548

549

async def main():

550

from mcp.server import stdio_server

551

552

options = await server.create_initialization_options()

553

554

async with stdio_server() as (read, write):

555

await server.run(read, write, options)

556

557

if __name__ == "__main__":

558

asyncio.run(main())

559

```

560

561

### Custom Lifespan Management

562

563

```python

564

from mcp.server import Server

565

import asyncio

566

import aiofiles

567

568

# Custom lifespan function

569

async def custom_lifespan(server_instance):

570

"""Custom server lifespan with setup and cleanup."""

571

print("Server starting up...")

572

573

# Setup: Initialize resources, connections, etc.

574

server_instance._data_file = await aiofiles.open("server_data.json", "w")

575

server_instance._active_connections = set()

576

577

try:

578

# Yield control to the server

579

yield

580

finally:

581

# Cleanup: Close resources, save state, etc.

582

print("Server shutting down...")

583

await server_instance._data_file.close()

584

print(f"Closed {len(server_instance._active_connections)} connections")

585

586

# Create server with custom lifespan

587

server = Server(

588

"lifecycle-server",

589

version="1.0.0",

590

lifespan=custom_lifespan

591

)

592

593

@server.list_tools()

594

async def list_tools():

595

"""Return simple tool list."""

596

return [

597

Tool(

598

name="status",

599

description="Get server status",

600

inputSchema={"type": "object", "properties": {}}

601

)

602

]

603

604

@server.call_tool()

605

async def call_tool(name: str, arguments: dict):

606

"""Handle tool calls with server state access."""

607

if name == "status":

608

connections = len(getattr(server, '_active_connections', []))

609

return [TextContent(

610

type="text",

611

text=f"Server is running with {connections} active connections"

612

)]

613

614

return [TextContent(type="text", text="Unknown tool")]

615

616

async def main():

617

from mcp.server import stdio_server

618

619

options = await server.create_initialization_options()

620

621

async with stdio_server() as (read, write):

622

await server.run(read, write, options)

623

624

if __name__ == "__main__":

625

asyncio.run(main())

626

```