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-tools.mddocs/

0

# Server Tools API

1

2

Tools enable LLMs to take actions through your MCP server. Tools are model-controlled - AI decides which tools to call and with what arguments.

3

4

## Registration

5

6

### Modern API (Recommended)

7

8

```typescript { .api }

9

server.registerTool<InputArgs extends ZodRawShape, OutputArgs extends ZodRawShape>(

10

name: string,

11

config: {

12

title?: string;

13

description?: string;

14

inputSchema?: InputArgs;

15

outputSchema?: OutputArgs;

16

annotations?: ToolAnnotations;

17

_meta?: Record<string, unknown>;

18

},

19

callback: (args: z.infer<ZodObject<InputArgs>>, extra: RequestHandlerExtra) => Promise<CallToolResult> | CallToolResult

20

): RegisteredTool;

21

```

22

23

### Examples

24

25

```typescript

26

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

27

import { z } from 'zod';

28

29

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

30

31

// Simple tool

32

server.registerTool('add', {

33

title: 'Addition Tool',

34

description: 'Add two numbers together',

35

inputSchema: {

36

a: z.number().describe('First number'),

37

b: z.number().describe('Second number')

38

},

39

outputSchema: {

40

result: z.number().describe('Sum of the two numbers')

41

}

42

}, async ({ a, b }) => {

43

const output = { result: a + b };

44

return {

45

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

46

structuredContent: output

47

};

48

});

49

50

// Tool with annotations

51

server.registerTool('fetch-data', {

52

title: 'Fetch External Data',

53

description: 'Fetch data from an external API',

54

inputSchema: {

55

url: z.string().url(),

56

method: z.enum(['GET', 'POST']).optional()

57

},

58

outputSchema: {

59

data: z.unknown(),

60

status: z.number()

61

},

62

annotations: {

63

audience: ['user']

64

}

65

}, async ({ url, method = 'GET' }) => {

66

const response = await fetch(url, { method });

67

const data = await response.json();

68

const output = { data, status: response.status };

69

return {

70

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

71

structuredContent: output

72

};

73

});

74

```

75

76

## Return Values

77

78

```typescript { .api }

79

interface CallToolResult {

80

content: ContentBlock[]; // Required: Content to return

81

isError?: boolean; // Optional: Indicates error

82

structuredContent?: Record<string, unknown>; // Required if outputSchema defined

83

_meta?: Record<string, unknown>;

84

}

85

```

86

87

### Content Block Types

88

89

```typescript { .api }

90

interface TextContent {

91

type: 'text';

92

text: string;

93

annotations?: { audience?: ('user' | 'assistant')[]; priority?: number; };

94

}

95

96

interface ImageContent { type: 'image'; data: string; mimeType: string; }

97

interface AudioContent { type: 'audio'; data: string; mimeType: string; }

98

interface EmbeddedResource {

99

type: 'resource';

100

resource: { uri: string; mimeType?: string; text?: string; blob?: string; };

101

}

102

interface ResourceLink {

103

type: 'resource_link';

104

uri: string;

105

name?: string;

106

mimeType?: string;

107

description?: string;

108

}

109

110

type ContentBlock = TextContent | ImageContent | AudioContent | EmbeddedResource | ResourceLink;

111

```

112

113

### Return Examples

114

115

```typescript

116

// Simple text

117

return {

118

content: [{ type: 'text', text: 'Operation completed successfully' }]

119

};

120

121

// With structured content (required if outputSchema defined)

122

return {

123

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

124

structuredContent: { count: 42 }

125

};

126

127

// Error result

128

return {

129

content: [{ type: 'text', text: 'Failed to process request' }],

130

isError: true

131

};

132

133

// Multiple content blocks with resource links

134

return {

135

content: [

136

{ type: 'text', text: 'Found 2 files' },

137

{ type: 'resource_link', uri: 'file:///project/README.md', name: 'README.md', mimeType: 'text/markdown' },

138

{ type: 'resource_link', uri: 'file:///project/index.ts', name: 'index.ts', mimeType: 'text/typescript' }

139

],

140

structuredContent: { count: 2, files: ['README.md', 'index.ts'] }

141

};

142

```

143

144

## Callback Signature

145

146

```typescript { .api }

147

type ToolCallback<Args extends ZodRawShape = undefined> = Args extends undefined

148

? (extra: RequestHandlerExtra) => Promise<CallToolResult> | CallToolResult

149

: (args: z.infer<ZodObject<Args>>, extra: RequestHandlerExtra) => Promise<CallToolResult> | CallToolResult;

150

151

interface RequestHandlerExtra {

152

signal: AbortSignal; // Cancellation signal

153

authInfo?: AuthInfo; // Validated access token info

154

sessionId?: string; // Session ID from transport

155

_meta?: RequestMeta; // Request metadata

156

requestId: RequestId; // JSON-RPC request ID

157

requestInfo?: RequestInfo; // HTTP request details

158

sendNotification: (notification: SendNotificationT) => Promise<void>;

159

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

160

}

161

```

162

163

## Managing Tools

164

165

```typescript { .api }

166

interface RegisteredTool {

167

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

168

disable(): void; // Hide from listTools

169

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

170

remove(): void; // Remove entirely

171

}

172

```

173

174

### Dynamic Control Example

175

176

```typescript

177

const tool = server.registerTool('admin-action', config, callback);

178

179

tool.disable(); // Initially disabled

180

181

// After authentication

182

tool.enable();

183

184

// Update description

185

tool.update({

186

description: 'Admin action (authenticated as user@example.com)'

187

});

188

189

// Remove when no longer needed

190

tool.remove();

191

```

192

193

## Error Handling

194

195

```typescript

196

server.registerTool('risky-operation', {

197

title: 'Risky Operation',

198

description: 'An operation that might fail',

199

inputSchema: { id: z.string() }

200

}, async ({ id }) => {

201

try {

202

const result = await performRiskyOperation(id);

203

return {

204

content: [{ type: 'text', text: `Success: ${result}` }],

205

structuredContent: { success: true, result }

206

};

207

} catch (error) {

208

return {

209

content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }],

210

isError: true

211

};

212

}

213

});

214

```

215

216

## Validation

217

218

- Input arguments are automatically validated before callback invocation

219

- Invalid inputs result in `ErrorCode.InvalidParams` error

220

- Output `structuredContent` is validated against `outputSchema` if provided

221

- Missing `structuredContent` when `outputSchema` is defined results in error

222

223

## Notifications

224

225

```typescript { .api }

226

server.sendToolListChanged(): void; // Notify clients of tool list changes

227

```

228

229

Tools are automatically notified when added, removed, enabled, or disabled (if client supports capability).

230

231

## Types Reference

232

233

```typescript { .api }

234

interface Tool {

235

name: string;

236

title?: string;

237

description?: string;

238

inputSchema: JSONSchema;

239

outputSchema?: JSONSchema;

240

annotations?: ToolAnnotations;

241

_meta?: Record<string, unknown>;

242

}

243

244

interface ToolAnnotations {

245

audience?: ('user' | 'assistant')[];

246

[key: string]: unknown;

247

}

248

249

interface ListToolsResult {

250

tools: Tool[];

251

nextCursor?: string;

252

}

253

```

254

255

## Legacy API

256

257

```typescript { .api }

258

server.tool(name: string, callback: ToolCallback): RegisteredTool;

259

server.tool(name: string, description: string, callback: ToolCallback): RegisteredTool;

260

server.tool<Args extends ZodRawShape>(name: string, paramsSchema: Args, callback: ToolCallback<Args>): RegisteredTool;

261

server.tool<Args extends ZodRawShape>(name: string, description: string, paramsSchema: Args, callback: ToolCallback<Args>): RegisteredTool;

262

```

263

264

Use `registerTool` for new code.

265