#
tokens: 43554/50000 25/26 files (page 1/2)
lines: off (toggle) GitHub
raw markdown copy
This is page 1 of 2. Use http://codebase.md/r3-yamauchi/kintone-mcp-server?page={x} to view the full context.

# Directory Structure

```
├── .gitignore
├── .mcpbignore
├── .npmrc
├── AGENTS.md
├── CLAUDE.md
├── docs
│   ├── images
│   │   ├── mcpb-install0.png
│   │   ├── mcpb-install1.png
│   │   ├── mcpb-install2.png
│   │   ├── mcpb-install3.png
│   │   ├── mcpb-install4.png
│   │   ├── mcpb-install5.png
│   │   ├── mcpb-install6.png
│   │   ├── mcpb-install7.png
│   │   ├── tool.png
│   │   └── tools.png
│   ├── mcp-server-architecture.md
│   ├── mcp-specification
│   │   ├── 2024-11-05.txt
│   │   └── 2025-03-26.txt
│   └── tool-annotations.md
├── LICENSE
├── manifest.json
├── package-lock.json
├── package.json
├── pnpm-lock.yaml
├── README.md
├── renovate.json
├── scripts
│   └── ensure-pnpm.js
├── server.js
├── src
│   ├── constants.js
│   ├── index.js
│   ├── models
│   │   ├── KintoneCredentials.js
│   │   └── KintoneRecord.js
│   ├── repositories
│   │   ├── base
│   │   │   ├── BaseKintoneRepository.js
│   │   │   └── http
│   │   │       ├── createKintoneClient.js
│   │   │       ├── KintoneApiError.js
│   │   │       └── KintoneHttpClient.js
│   │   ├── KintoneAppRepository.js
│   │   ├── KintoneFileRepository.js
│   │   ├── KintoneFormRepository.js
│   │   ├── KintonePreviewRepository.js
│   │   ├── KintoneRecordRepository.js
│   │   ├── KintoneRepository.js
│   │   ├── KintoneSpaceRepository.js
│   │   ├── KintoneUserRepository.js
│   │   └── validators
│   │       ├── FieldValidator.js
│   │       ├── LayoutValidator.js
│   │       └── OptionValidator.js
│   ├── server
│   │   ├── handlers
│   │   │   ├── ErrorHandlers.js
│   │   │   ├── ToolRequestHandler.js
│   │   │   └── ToolRouter.js
│   │   ├── MCPServer.js
│   │   └── tools
│   │       ├── AppTools.js
│   │       ├── BaseToolHandler.js
│   │       ├── definitions
│   │       │   ├── AppToolDefinitions.js
│   │       │   ├── DocumentationToolDefinitions.js
│   │       │   ├── FieldToolDefinitions.js
│   │       │   ├── FileToolDefinitions.js
│   │       │   ├── index.js
│   │       │   ├── LayoutToolDefinitions.js
│   │       │   ├── RecordToolDefinitions.js
│   │       │   ├── SpaceToolDefinitions.js
│   │       │   ├── SystemToolDefinitions.js
│   │       │   └── UserToolDefinitions.js
│   │       ├── documentation
│   │       │   ├── calcField.js
│   │       │   ├── choiceFields.js
│   │       │   ├── dateField.js
│   │       │   ├── dateTimeField.js
│   │       │   ├── fileField.js
│   │       │   ├── index.js
│   │       │   ├── layoutFields.js
│   │       │   ├── linkField.js
│   │       │   ├── lookup.js
│   │       │   ├── numberField.js
│   │       │   ├── otherFields.js
│   │       │   ├── queryLanguage.js
│   │       │   ├── referenceTable.js
│   │       │   ├── richText.js
│   │       │   ├── subtable.js
│   │       │   ├── systemFields.js
│   │       │   ├── textFields.js
│   │       │   ├── timeField.js
│   │       │   └── userSelect.js
│   │       ├── DocumentationTools.js
│   │       ├── FieldTools.js
│   │       ├── FileTools.js
│   │       ├── LayoutTools.js
│   │       ├── RecordTools.js
│   │       ├── SpaceTools.js
│   │       ├── SystemTools.js
│   │       └── UserTools.js
│   └── utils
│       ├── DataTransformers.js
│       ├── FieldValidationUtils.js
│       ├── index.js
│       ├── LayoutUtils.js
│       ├── LoggingUtils.js
│       ├── ResponseBuilder.js
│       └── ValidationUtils.js
└── unofficial-kintone-mcp-server-8.0.0.mcpb
```

# Files

--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------

```
minimumReleaseAge=1440

```

--------------------------------------------------------------------------------
/.mcpbignore:
--------------------------------------------------------------------------------

```
.env
.github/
docs/
AGENTS.md
CLAUDE.md
llms-install.md
renovate.json
```

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
# Package manager configuration
.pnpm-store/

# Standalone build artifacts
standalone/
standalone-package/
*.tgz

# Test directories
test-package/
coverage/

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage
*.lcov

# nyc test coverage
.nyc_output

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# Snowpack dependency directory (https://snowpack.dev/)
web_modules/

# TypeScript cache
*.tsbuildinfo

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional stylelint cache
.stylelintcache

# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local

# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache

# Next.js build output
.next
out

# Nuxt.js build / generate output
.nuxt
dist

# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public

# vuepress build output
.vuepress/dist

# vuepress v2.x temp and cache directory
.temp
.cache

# Docusaurus cache and generated files
.docusaurus

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

# TernJS port file
.tern-port

# Stores VSCode versions used for testing VSCode extensions
.vscode-test

# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*

# Project specific files
.clinerules
.clinerules/

# Editor directories and files
.idea/
.vscode/
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

# OS generated files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db

# Local config files
*.local.js
config.local.js

```

--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------

```javascript
#!/usr/bin/env node
import './src/index.js';

```

--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------

```json
{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": [
    "config:recommended"
  ]
}

```

--------------------------------------------------------------------------------
/src/models/KintoneRecord.js:
--------------------------------------------------------------------------------

```javascript
// src/models/KintoneRecord.js
export class KintoneRecord {
    constructor(appId, recordId, fields) {
        this.appId = appId;
        this.recordId = recordId;
        this.fields = fields;
    }
}

```

--------------------------------------------------------------------------------
/src/models/KintoneCredentials.js:
--------------------------------------------------------------------------------

```javascript
// src/models/KintoneCredentials.js
export class KintoneCredentials {
    constructor(domain, username, password) {
        this.domain = domain;
        this.username = username;
        this.password = password;
        this.auth = Buffer.from(`${username}:${password}`).toString('base64');
    }
}

```

--------------------------------------------------------------------------------
/src/utils/index.js:
--------------------------------------------------------------------------------

```javascript
// src/utils/index.js
export { ValidationUtils } from './ValidationUtils.js';
export { LoggingUtils } from './LoggingUtils.js';
export { ResponseBuilder } from './ResponseBuilder.js';
export { FieldValidationUtils } from './FieldValidationUtils.js';
export { DataTransformers } from './DataTransformers.js';
export { LayoutUtils } from './LayoutUtils.js';
```

--------------------------------------------------------------------------------
/src/repositories/base/http/KintoneApiError.js:
--------------------------------------------------------------------------------

```javascript
// src/repositories/base/http/KintoneApiError.js
export class KintoneApiError extends Error {
    constructor(message, { status = null, code = null, errors = null, responseBody = null } = {}) {
        super(message);
        this.name = 'KintoneApiError';
        this.status = status;
        this.code = code;
        this.errors = errors;
        this.responseBody = responseBody;
    }
}

```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
{
  "name": "unofficial-kintone-mcp-server",
  "version": "8.0.0",
  "packageManager": "[email protected]",
  "main": "server.js",
  "type": "module",
  "scripts": {
    "start": "node server.js",
    "test": "node --test"
  },
  "keywords": [
    "modelcontextprotocol",
    "mcp",
    "kintone"
  ],
  "author": {
    "name": "r3-yamauchi",
    "url": "https://www.r3it.com/blog/author/yamauchi"
  },
  "license": "AGPL-3.0",
  "description": "MCP server for kintone (Unofficial)",
  "engines": {
    "node": ">=20"
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "1.18.2"
  }
}

```

--------------------------------------------------------------------------------
/src/utils/DataTransformers.js:
--------------------------------------------------------------------------------

```javascript
import { LoggingUtils } from './LoggingUtils.js';

export function convertDropdownFieldType(obj) {
    if (!obj || typeof obj !== 'object') return;
    
    for (const key in obj) {
        if (Object.prototype.hasOwnProperty.call(obj, key)) {
            const value = obj[key];
            
            if (key === 'type' && value === 'DROPDOWN') {
                obj[key] = 'DROP_DOWN';
                LoggingUtils.debug('field', 'dropdown_type_normalized', { property: key });
            }
            else if (key === 'field_type' && value === 'DROPDOWN') {
                obj[key] = 'DROP_DOWN';
                LoggingUtils.debug('field', 'dropdown_type_normalized', { property: key });
            }
            else if (value && typeof value === 'object') {
                convertDropdownFieldType(value);
            }
        }
    }
}

```

--------------------------------------------------------------------------------
/src/server/tools/definitions/index.js:
--------------------------------------------------------------------------------

```javascript
// src/server/tools/definitions/index.js

import { recordToolDefinitions } from './RecordToolDefinitions.js';
import { appToolDefinitions } from './AppToolDefinitions.js';
import { spaceToolDefinitions } from './SpaceToolDefinitions.js';
import { fieldToolDefinitions } from './FieldToolDefinitions.js';
import { documentationToolDefinitions } from './DocumentationToolDefinitions.js';
import { layoutToolDefinitions } from './LayoutToolDefinitions.js';
import { userToolDefinitions } from './UserToolDefinitions.js';
import { systemToolDefinitions } from './SystemToolDefinitions.js';
import { fileToolDefinitions } from './FileToolDefinitions.js';

/**
 * 全てのツール定義をフラットな配列として提供
 */
export const allToolDefinitions = [
    ...recordToolDefinitions,
    ...appToolDefinitions,
    ...spaceToolDefinitions,
    ...fieldToolDefinitions,
    ...documentationToolDefinitions,
    ...layoutToolDefinitions,
    ...userToolDefinitions,
    ...systemToolDefinitions,
    ...fileToolDefinitions
];

```

--------------------------------------------------------------------------------
/src/server/tools/UserTools.js:
--------------------------------------------------------------------------------

```javascript
// src/server/tools/UserTools.js
import { ValidationUtils } from '../../utils/ValidationUtils.js';
import { LoggingUtils } from '../../utils/LoggingUtils.js';
import { ResponseBuilder } from '../../utils/ResponseBuilder.js';

// ユーザー関連のツールを処理する関数
export async function handleUserTools(name, args, repository) {
    // 共通のツール実行ログ
    LoggingUtils.logToolExecution('user', name, args);
    switch (name) {
        case 'get_users': {
            const codes = args.codes || [];
            
            if (codes.length > 0) {
                ValidationUtils.validateArray(codes, 'codes');
            }
            
            return repository.getUsers(codes);
        }
        
        case 'get_groups': {
            const codes = args.codes || [];
            
            if (codes.length > 0) {
                ValidationUtils.validateArray(codes, 'codes');
            }
            
            return repository.getGroups(codes);
        }
        
        case 'get_group_users': {
            ValidationUtils.validateRequired(args, ['group_code']);
            ValidationUtils.validateString(args.group_code, 'group_code');
            
            return repository.getGroupUsers(args.group_code);
        }
        
        default:
            throw new Error(`Unknown user tool: ${name}`);
    }
}

```

--------------------------------------------------------------------------------
/src/repositories/KintoneFileRepository.js:
--------------------------------------------------------------------------------

```javascript
// src/repositories/KintoneFileRepository.js
import { BaseKintoneRepository } from './base/BaseKintoneRepository.js';
import { LoggingUtils } from '../utils/LoggingUtils.js';

export class KintoneFileRepository extends BaseKintoneRepository {
    async uploadFile(fileName, fileData) {
        try {
            LoggingUtils.logDetailedOperation('uploadFile', 'ファイルアップロード開始', { fileName });
            const buffer = Buffer.from(fileData, 'base64');
            const response = await this.client.file.uploadFile({
                file: {
                    name: fileName,
                    data: buffer
                }
            });
            LoggingUtils.logDetailedOperation('uploadFile', 'ファイルアップロード完了', { 
                fileName,
                fileKey: response.fileKey 
            });
            return response;
        } catch (error) {
            this.handleKintoneError(error, `upload file ${fileName}`);
        }
    }

    async downloadFile(fileKey) {
        try {
            LoggingUtils.logDetailedOperation('downloadFile', 'ファイルダウンロード開始', { fileKey });
            const response = await this.client.file.downloadFile({ fileKey: fileKey });
            LoggingUtils.logDetailedOperation('downloadFile', 'ファイルダウンロード完了', { 
                fileKey,
                contentType: response.contentType || 'unknown' 
            });
            return response;
        } catch (error) {
            this.handleKintoneError(error, `download file with key ${fileKey}`);
        }
    }
}

```

--------------------------------------------------------------------------------
/src/server/handlers/ToolRequestHandler.js:
--------------------------------------------------------------------------------

```javascript
import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
import { ToolRouter } from './ToolRouter.js';
import { convertDropdownFieldType } from '../../utils/DataTransformers.js';
import { handleToolError } from './ErrorHandlers.js';
import { LoggingUtils } from '../../utils/LoggingUtils.js';

export async function executeToolRequest(request, repository) {
    const { name, arguments: args } = request.params;
    LoggingUtils.info('tool', 'tool_request_received', { name });
    LoggingUtils.debug('tool', 'tool_request_payload', request.params);
    
    if (!name) {
        throw new McpError(
            ErrorCode.InvalidParams,
            `ツール名が指定されていません。`
        );
    }
    
    if (!args) {
        throw new McpError(
            ErrorCode.InvalidParams,
            `ツール "${name}" の引数が指定されていません。`
        );
    }
    
    convertDropdownFieldType(args);
    
    LoggingUtils.info('tool', 'tool_execution_start', { name });
    LoggingUtils.debug('tool', 'tool_arguments', args);

    try {
        const router = new ToolRouter();
        
        const lookupResponse = router.handleLookupFieldSpecialCase(name, args, repository);
        if (lookupResponse) {
            return await lookupResponse;
        }
        
        const result = await router.routeToolRequest(name, args, repository);
        
        return {
            content: [
                {
                    type: 'text',
                    text: JSON.stringify(result, null, 2)
                }
            ]
        };
    } catch (error) {
        return handleToolError(error);
    }
}

```

--------------------------------------------------------------------------------
/src/server/MCPServer.js:
--------------------------------------------------------------------------------

```javascript
// src/server/MCPServer.js
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
    CallToolRequestSchema,
    ListToolsRequestSchema,
    ListPromptsRequestSchema,
    ListResourcesRequestSchema,
    GetPromptRequestSchema,
    ListResourceTemplatesRequestSchema,
    ReadResourceRequestSchema,
    McpError,
    ErrorCode,
} from '@modelcontextprotocol/sdk/types.js';
import { KintoneCredentials } from '../models/KintoneCredentials.js';
import { KintoneRepository } from '../repositories/KintoneRepository.js';
import { executeToolRequest } from './handlers/ToolRequestHandler.js';
import { allToolDefinitions } from './tools/definitions/index.js';
import { LoggingUtils } from '../utils/LoggingUtils.js';

export class MCPServer {
    constructor(domain, username, password) {
        this.credentials = new KintoneCredentials(domain, username, password);
        this.repository = new KintoneRepository(this.credentials);
        
        this.server = new Server(
            {
                name: 'kintonemcp',
                version: '8.0.0',
            },
            {
                capabilities: {
                    tools: {},
                    prompts: {},
                    resources: {},
                },
            }
        );
        
        this.setupRequestHandlers();
        
        // エラーハンドリング
        this.server.onerror = (error) => LoggingUtils.error('server', 'mcp_server_error', error);
        process.on('SIGINT', async () => {
            await this.server.close();
            process.exit(0);
        });
    }
    
    setupRequestHandlers() {
        // ツール一覧を返すハンドラー
        this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
            tools: allToolDefinitions
        }));
        
        // プロンプト一覧(未提供のため空配列)
        this.server.setRequestHandler(ListPromptsRequestSchema, async () => ({
            prompts: []
        }));
        this.server.setRequestHandler(GetPromptRequestSchema, async () => {
            throw new McpError(ErrorCode.MethodNotFound, 'promptは提供されていません');
        });

        // リソース一覧(未提供のため空配列)
        this.server.setRequestHandler(ListResourcesRequestSchema, async () => ({
            resources: []
        }));
        this.server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => ({
            resourceTemplates: []
        }));
        this.server.setRequestHandler(ReadResourceRequestSchema, async () => {
            throw new McpError(ErrorCode.MethodNotFound, 'resourceは提供されていません');
        });
        
        // ツールリクエストを実行するハンドラー
        this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
            return executeToolRequest(request, this.repository);
        });
    }
    
    async run() {
        const transport = new StdioServerTransport();
        await this.server.connect(transport);
        LoggingUtils.info('server', 'mcp_server_running');
    }
}

```

--------------------------------------------------------------------------------
/src/server/tools/SpaceTools.js:
--------------------------------------------------------------------------------

```javascript
// src/server/tools/SpaceTools.js
import { ValidationUtils } from '../../utils/ValidationUtils.js';
import { LoggingUtils } from '../../utils/LoggingUtils.js';
import { ResponseBuilder } from '../../utils/ResponseBuilder.js';

// スペース関連のツールを処理する関数
export async function handleSpaceTools(name, args, repository) {
    // 共通のツール実行ログ
    LoggingUtils.logToolExecution('space', name, args);
    
    switch (name) {
        case 'get_space': {
            ValidationUtils.validateRequired(args, ['space_id']);
            
            return repository.getSpace(args.space_id);
        }
        
        case 'update_space': {
            ValidationUtils.validateRequired(args, ['space_id']);
            
            await repository.updateSpace(args.space_id, {
                name: args.name,
                isPrivate: args.isPrivate,
                fixedMember: args.fixedMember,
                useMultiThread: args.useMultiThread,
            });
            return ResponseBuilder.success();
        }
        
        case 'update_space_body': {
            ValidationUtils.validateRequired(args, ['space_id', 'body']);
            ValidationUtils.validateString(args.body, 'body');
            
            await repository.updateSpaceBody(args.space_id, args.body);
            return ResponseBuilder.success();
        }
        
        case 'get_space_members': {
            ValidationUtils.validateRequired(args, ['space_id']);
            
            return repository.getSpaceMembers(args.space_id);
        }
        
        case 'update_space_members': {
            ValidationUtils.validateRequired(args, ['space_id', 'members']);
            ValidationUtils.validateArray(args.members, 'members');
            
            await repository.updateSpaceMembers(args.space_id, args.members);
            return ResponseBuilder.success();
        }
        
        case 'add_thread': {
            ValidationUtils.validateRequired(args, ['space_id', 'name']);
            ValidationUtils.validateString(args.name, 'name');
            
            const response = await repository.addThread(args.space_id, args.name);
            return ResponseBuilder.withId('thread_id', response.id);
        }
        
        case 'update_thread': {
            ValidationUtils.validateRequired(args, ['thread_id']);
            
            await repository.updateThread(args.thread_id, {
                name: args.name,
                body: args.body,
            });
            return ResponseBuilder.success();
        }
        
        case 'add_thread_comment': {
            ValidationUtils.validateRequired(args, ['space_id', 'thread_id', 'text']);
            ValidationUtils.validateString(args.text, 'text');
            
            const response = await repository.addThreadComment(
                args.space_id,
                args.thread_id,
                {
                    text: args.text,
                    mentions: args.mentions || [],
                }
            );
            return ResponseBuilder.withId('comment_id', response.id);
        }
        
        case 'add_guests': {
            ValidationUtils.validateRequired(args, ['guests']);
            ValidationUtils.validateArray(args.guests, 'guests', { minLength: 1 });
            
            await repository.addGuests(args.guests);
            return ResponseBuilder.success();
        }
        
        case 'update_space_guests': {
            ValidationUtils.validateRequired(args, ['space_id', 'guests']);
            ValidationUtils.validateArray(args.guests, 'guests');
            
            await repository.updateSpaceGuests(args.space_id, args.guests);
            return ResponseBuilder.success();
        }
        
        default:
            throw new Error(`Unknown space tool: ${name}`);
    }
}
```

--------------------------------------------------------------------------------
/src/repositories/KintoneSpaceRepository.js:
--------------------------------------------------------------------------------

```javascript
// src/repositories/KintoneSpaceRepository.js
import { BaseKintoneRepository } from './base/BaseKintoneRepository.js';
import { LoggingUtils } from '../utils/LoggingUtils.js';
import { ResponseBuilder } from '../utils/ResponseBuilder.js';

export class KintoneSpaceRepository extends BaseKintoneRepository {
    async getSpace(spaceId) {
        try {
            LoggingUtils.logDetailedOperation('getSpace', 'スペース情報取得', { spaceId });
            const response = await this.client.space.getSpace({ id: spaceId });
            LoggingUtils.logDetailedOperation('getSpace', 'スペース情報取得完了', { spaceId });
            return response;
        } catch (error) {
            this.handleKintoneError(error, `get space ${spaceId}`);
        }
    }

    async updateSpace(spaceId, settings) {
        try {
            LoggingUtils.logDetailedOperation('updateSpace', 'スペース情報更新', { spaceId, settings });
            await this.client.space.updateSpace({
                id: spaceId,
                ...settings
            });
            LoggingUtils.logDetailedOperation('updateSpace', 'スペース情報更新完了', { spaceId });
        } catch (error) {
            this.handleKintoneError(error, `update space ${spaceId}`);
        }
    }

    async updateSpaceBody(spaceId, body) {
        try {
            LoggingUtils.logDetailedOperation('updateSpaceBody', 'スペース本文更新', { spaceId, bodyLength: body.length });
            await this.client.space.updateSpaceBody({
                id: spaceId,
                body: body
            });
            LoggingUtils.logDetailedOperation('updateSpaceBody', 'スペース本文更新完了', { spaceId });
        } catch (error) {
            this.handleKintoneError(error, `update space body ${spaceId}`);
        }
    }

    async getSpaceMembers(spaceId) {
        try {
            LoggingUtils.logDetailedOperation('getSpaceMembers', 'スペースメンバー取得', { spaceId });
            const response = await this.client.space.getSpaceMembers({ id: spaceId });
            LoggingUtils.logDetailedOperation('getSpaceMembers', 'スペースメンバー取得完了', { 
                spaceId, 
                memberCount: response.members ? response.members.length : 0 
            });
            return response;
        } catch (error) {
            this.handleKintoneError(error, `get space members ${spaceId}`);
        }
    }

    async updateSpaceMembers(spaceId, members) {
        try {
            LoggingUtils.logDetailedOperation('updateSpaceMembers', 'スペースメンバー更新', { 
                spaceId, 
                memberCount: members.length 
            });
            await this.client.space.updateSpaceMembers({
                id: spaceId,
                members: members
            });
            LoggingUtils.logDetailedOperation('updateSpaceMembers', 'スペースメンバー更新完了', { spaceId });
        } catch (error) {
            this.handleKintoneError(error, `update space members ${spaceId}`);
        }
    }

    async addThread(spaceId, name) {
        try {
            LoggingUtils.logDetailedOperation('addThread', 'スレッド作成', { spaceId, threadName: name });
            const response = await this.client.space.addThread({
                space: spaceId,
                name: name
            });
            LoggingUtils.logDetailedOperation('addThread', 'スレッド作成完了', { 
                spaceId, 
                threadId: response.id 
            });
            return response;
        } catch (error) {
            this.handleKintoneError(error, `add thread to space ${spaceId}`);
        }
    }

    async updateThread(threadId, params) {
        try {
            LoggingUtils.logDetailedOperation('updateThread', 'スレッド更新', { threadId, params });
            await this.client.space.updateThread({
                id: threadId,
                ...params
            });
            LoggingUtils.logDetailedOperation('updateThread', 'スレッド更新完了', { threadId });
        } catch (error) {
            this.handleKintoneError(error, `update thread ${threadId}`);
        }
    }

    async addThreadComment(spaceId, threadId, comment) {
        try {
            LoggingUtils.logDetailedOperation('addThreadComment', 'コメント追加', { 
                spaceId, 
                threadId, 
                commentLength: comment.text ? comment.text.length : 0 
            });
            const response = await this.client.space.addThreadComment({
                space: spaceId,
                thread: threadId,
                comment: comment
            });
            LoggingUtils.logDetailedOperation('addThreadComment', 'コメント追加完了', { 
                commentId: response.id 
            });
            return response;
        } catch (error) {
            this.handleKintoneError(error, `add comment to thread ${threadId}`);
        }
    }

    async updateSpaceGuests(spaceId, guests) {
        try {
            LoggingUtils.logDetailedOperation('updateSpaceGuests', 'スペースゲスト更新', { 
                spaceId, 
                guestCount: guests.length 
            });
            await this.client.space.updateSpaceGuests({
                id: spaceId,
                guests: guests
            });
            LoggingUtils.logDetailedOperation('updateSpaceGuests', 'スペースゲスト更新完了', { spaceId });
        } catch (error) {
            this.handleKintoneError(error, `update space guests ${spaceId}`);
        }
    }
}

```

--------------------------------------------------------------------------------
/src/server/handlers/ToolRouter.js:
--------------------------------------------------------------------------------

```javascript
import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
import { handleRecordTools } from '../tools/RecordTools.js';
import { handleAppTools } from '../tools/AppTools.js';
import { handleSpaceTools } from '../tools/SpaceTools.js';
import { handleFieldTools } from '../tools/FieldTools.js';
import { handleDocumentationTools } from '../tools/DocumentationTools.js';
import { handleLayoutTools } from '../tools/LayoutTools.js';
import { handleUserTools } from '../tools/UserTools.js';
import { handleSystemTools } from '../tools/SystemTools.js';
import { handleFileTools } from '../tools/FileTools.js';
import { LoggingUtils } from '../../utils/LoggingUtils.js';

export class ToolRouter {
    constructor() {
        this.toolCategories = {
            record: {
                tools: ['get_record', 'search_records', 'create_record', 'update_record', 'add_record_comment', 
                       'update_record_status', 'update_record_assignees',
                       'get_record_comments', 'update_record_comment', 'create_records', 'upsert_record',
                       'upsert_records'],
                handler: handleRecordTools
            },
            app: {
                tools: [
                    'create_app', 'deploy_app', 'get_deploy_status', 'update_app_settings', 'get_apps_info',
                    'get_form_layout', 'get_form_fields', 'update_form_layout', 'get_preview_app_settings',
                    'get_preview_form_fields', 'get_preview_form_layout',
                    'move_app_to_space', 'move_app_from_space', 'get_app_actions', 'get_app_plugins',
                    'get_process_management', 'update_process_management', 'get_views', 'update_views', 'get_app_acl',
                    'get_field_acl', 'update_field_acl', 'get_reports', 'update_reports',
                    'get_notifications', 'update_notifications', 'get_per_record_notifications', 'update_per_record_notifications',
                    'get_reminder_notifications', 'update_reminder_notifications', 'update_app_actions', 'update_plugins',
                    'get_app_customize', 'update_app_customize', 'update_app_acl', 'get_record_acl', 'evaluate_records_acl'
                ],
                handler: handleAppTools
            },
            space: {
                tools: [
                    'get_space', 'update_space', 'update_space_body', 'get_space_members',
                    'update_space_members', 'add_thread', 'update_thread', 'add_thread_comment',
                    'add_guests', 'update_space_guests'
                ],
                handler: handleSpaceTools
            },
            field: {
                tools: [
                    'add_fields', 'update_field', 'create_choice_field', 'create_reference_table_field',
                    'create_text_field', 'create_number_field', 'create_date_field', 'create_time_field',
                    'create_datetime_field', 'create_rich_text_field', 'create_attachment_field',
                    'create_user_select_field', 'create_subtable_field', 'create_calc_field',
                    'create_status_field', 'create_related_records_field', 'create_link_field'
                ],
                handler: handleFieldTools
            },
            documentation: {
                tools: [
                    'get_field_type_documentation', 'get_available_field_types',
                    'get_documentation_tool_description', 'get_field_creation_tool_description',
                    'get_group_element_structure', 'get_query_language_documentation'
                ],
                handler: handleDocumentationTools
            },
            file: {
                tools: ['upload_file', 'download_file'],
                handler: handleFileTools
            },
            layout: {
                tools: [
                    'create_form_layout', 'update_form_layout', 'add_layout_element',
                    'create_group_layout', 'create_table_layout'
                ],
                handler: handleLayoutTools
            },
            user: {
                tools: ['get_users', 'get_groups', 'get_group_users'],
                handler: handleUserTools
            },
            system: {
                tools: ['get_kintone_domain', 'get_kintone_username'],
                handler: handleSystemTools
            }
        };
    }

    findToolCategory(toolName) {
        for (const [categoryName, category] of Object.entries(this.toolCategories)) {
            if (category.tools.includes(toolName)) {
                return { categoryName, handler: category.handler };
            }
        }
        return null;
    }

    async routeToolRequest(toolName, args, repository) {
        const toolCategory = this.findToolCategory(toolName);
        
        if (!toolCategory) {
            throw new McpError(
                ErrorCode.MethodNotFound,
                `Unknown tool: ${toolName}`
            );
        }

        return await toolCategory.handler(toolName, args, repository);
    }

    handleLookupFieldSpecialCase(toolName, args, repository) {
        if (toolName !== 'create_lookup_field') {
            return null;
        }

        return this.createLookupFieldResponse(args, repository);
    }

    async createLookupFieldResponse(args, repository) {
        const fieldConfig = await handleFieldTools('create_lookup_field', args, repository);

        const note = `注意: create_lookup_field ツールは設定オブジェクトを生成するだけのヘルパーツールです。実際にフィールドを追加するには、この結果を add_fields ツールに渡してください。`;
        const lookupNote = `
【重要】ルックアップフィールドについて
- ルックアップフィールドは基本的なフィールドタイプ(SINGLE_LINE_TEXT、NUMBERなど)に、lookup属性を追加したものです
- フィールドタイプとして "LOOKUP" を指定するのではなく、適切な基本タイプを指定し、その中にlookupプロパティを設定します
- 参照先アプリは運用環境にデプロイされている必要があります
- ルックアップのキーフィールド自体はフィールドマッピングに含めないでください
- lookupPickerFieldsとsortは省略可能ですが、指定することを強く推奨します
`;
        const example = `使用例:
add_fields({
  app_id: アプリID,
  properties: {
    "${fieldConfig.code}": ${JSON.stringify(fieldConfig, null, 2)}
  }
});`;
        LoggingUtils.info('field', 'lookup_field_guidance_generated', { fieldCode: fieldConfig.code });
        
        const result = {
            ...fieldConfig,
            _note: note,
            _lookupNote: lookupNote,
            _example: example
        };
        
        return {
            content: [
                {
                    type: 'text',
                    text: JSON.stringify(result, null, 2)
                },
                {
                    type: 'text',
                    text: note
                },
                {
                    type: 'text',
                    text: lookupNote
                },
                {
                    type: 'text',
                    text: example
                }
            ]
        };
    }
}

```

--------------------------------------------------------------------------------
/src/repositories/base/http/KintoneHttpClient.js:
--------------------------------------------------------------------------------

```javascript
// src/repositories/base/http/KintoneHttpClient.js
import { KintoneApiError } from './KintoneApiError.js';

const DEFAULT_TIMEOUT_MS = 60000;

function buildPath({ endpointName, guestSpaceId, preview = false }) {
    const guestPath = guestSpaceId !== undefined && guestSpaceId !== null
        ? `/guest/${guestSpaceId}`
        : '';
    const previewPath = preview ? '/preview' : '';
    return `/k${guestPath}/v1${previewPath}/${endpointName}.json`;
}

const FORM_DATA_SUPPORTED = typeof FormData !== 'undefined';

function isFormData(value) {
    return FORM_DATA_SUPPORTED && value instanceof FormData;
}

function stripUndefined(value) {
    if (value === null || value === undefined) {
        return undefined;
    }
    if (Array.isArray(value)) {
        return value.map(stripUndefined);
    }
    if (typeof value === 'object' && !isFormData(value) && !(value instanceof Date) && !(value instanceof Buffer)) {
        const result = {};
        for (const [key, entry] of Object.entries(value)) {
            if (entry !== undefined) {
                const cleaned = stripUndefined(entry);
                if (cleaned !== undefined) {
                    result[key] = cleaned;
                }
            }
        }
        return result;
    }
    return value;
}

export class KintoneHttpClient {
    constructor(credentials) {
        this.credentials = credentials;
        this.baseUrl = `https://${credentials.domain}`;
        this.authHeader = Buffer.from(`${credentials.username}:${credentials.password}`).toString('base64');
    }

    getDefaultHeaders() {
        return {
            'X-Cybozu-Authorization': this.authHeader,
            'X-Requested-With': 'XMLHttpRequest',
            'Accept': 'application/json'
        };
    }

    async request(method, endpointName, { params, data, preview = false, headers = {}, responseType, rawResponse = false } = {}) {
        const path = buildPath({
            endpointName,
            guestSpaceId: this.credentials.guestSpaceId,
            preview
        });
        const url = new URL(path, this.baseUrl);

        const cleanedParams = params ? stripUndefined(params) : undefined;
        if (cleanedParams) {
            for (const [key, value] of Object.entries(cleanedParams)) {
                if (value === undefined || value === null) {
                    continue;
                }
                if (Array.isArray(value)) {
                    for (const item of value) {
                        if (item !== undefined && item !== null) {
                            url.searchParams.append(key, String(item));
                        }
                    }
                } else {
                    url.searchParams.append(key, String(value));
                }
            }
        }

        const requestHeaders = new Headers(this.getDefaultHeaders());
        for (const [key, value] of Object.entries(headers)) {
            if (value !== undefined && value !== null) {
                requestHeaders.set(key, String(value));
            }
        }

        const init = {
            method: method.toUpperCase(),
            headers: requestHeaders,
            signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS)
        };

        const expectedResponseType = responseType || 'json';

        if (data !== undefined) {
            if (isFormData(data)) {
                // fetchがboundary付きヘッダーを自動付与するため、Content-Typeは削除
                requestHeaders.delete('Content-Type');
                init.body = data;
            } else {
                const payload = stripUndefined(data);
                init.body = JSON.stringify(payload);
                if (!requestHeaders.has('Content-Type')) {
                    requestHeaders.set('Content-Type', 'application/json');
                }
            }
        }

        let response;
        try {
            response = await fetch(url, init);
        } catch (error) {
            if (error instanceof KintoneApiError) {
                throw error;
            }
            const isAbortError = error?.name === 'AbortError';
            throw new KintoneApiError(
                isAbortError ? 'kintone API request timed out' : 'kintone API request failed without response',
                {
                    status: null,
                    responseBody: null
                }
            );
        }

        const parseErrorBody = async () => {
            const contentType = response.headers.get('content-type') || '';
            if (contentType.includes('application/json')) {
                try {
                    return await response.json();
                } catch (parseError) {
                    return null;
                }
            }
            try {
                return await response.text();
            } catch (parseError) {
                return null;
            }
        };

        if (!response.ok) {
            const body = await parseErrorBody();
            const message = typeof body === 'object' && body?.message
                ? body.message
                : `kintone API request failed with status ${response.status}`;

            throw new KintoneApiError(message, {
                status: response.status,
                code: typeof body === 'object' ? body?.code : undefined,
                errors: typeof body === 'object' ? body?.errors : undefined,
                responseBody: body
            });
        }

        if (rawResponse) {
            const dataBuffer = expectedResponseType === 'arraybuffer'
                ? Buffer.from(await response.arrayBuffer())
                : await response.text();
            return {
                data: dataBuffer,
                headers: Object.fromEntries(response.headers.entries()),
                status: response.status
            };
        }

        if (expectedResponseType === 'arraybuffer') {
            return Buffer.from(await response.arrayBuffer());
        }

        if (expectedResponseType === 'text') {
            return await response.text();
        }

        if (response.status === 204) {
            return null;
        }

        const text = await response.text();
        if (!text) {
            return {};
        }

        try {
            return JSON.parse(text);
        } catch (error) {
            throw new KintoneApiError('kintone API returned invalid JSON response', {
                status: response.status,
                responseBody: text
            });
        }
    }

    get(endpointName, params, options = {}) {
        return this.request('get', endpointName, { ...options, params });
    }

    post(endpointName, data, options = {}) {
        return this.request('post', endpointName, { ...options, data });
    }

    put(endpointName, data, options = {}) {
        return this.request('put', endpointName, { ...options, data });
    }

    delete(endpointName, data, options = {}) {
        return this.request('delete', endpointName, { ...options, data });
    }
}

```

--------------------------------------------------------------------------------
/src/repositories/KintoneRecordRepository.js:
--------------------------------------------------------------------------------

```javascript
// src/repositories/KintoneRecordRepository.js
import { BaseKintoneRepository } from './base/BaseKintoneRepository.js';
import { KintoneRecord } from '../models/KintoneRecord.js';
import { LoggingUtils } from '../utils/LoggingUtils.js';

export class KintoneRecordRepository extends BaseKintoneRepository {
    async getRecord(appId, recordId) {
        const params = { app: appId, id: recordId };
        return this.executeWithDetailedLogging(
            'getRecord',
            params,
            () => this.client.record.getRecord(params),
            `get record ${appId}/${recordId}`
        ).then(response => new KintoneRecord(appId, recordId, response.record));
    }

    async searchRecords(appId, query, fields = []) {
        const params = { app: appId };

        // クエリ文字列の処理
        if (query) {
            // クエリ文字列が order や limit のみで構成されているかチェック
            // 条件句の検出: 比較/文字列/集合/空判定(is empty / is not empty)をサポート
            const hasCondition = /[^\s]+(?:\s*(?:=|!=|>|<|>=|<=|like|in|not\s+in)|\s+is\s+(?:not\s+)?empty)/i.test(query);
            const hasOrderOrLimit = /(order |limit )/i.test(query);

            // order や limit のみの場合、$id > 0 を先頭に挿入
            if (!hasCondition && hasOrderOrLimit) {
                params.query = `$id > 0 ${query}`;
                LoggingUtils.logOperation('Modified query', params.query);
            } else {
                params.query = query;
            }
        }

        if (fields.length > 0) {
            params.fields = fields;
        }

        // getAllRecords ではなく getRecords を使用
        return this.executeWithDetailedLogging(
            'searchRecords',
            params,
            () => this.client.record.getRecords(params),
            `search records ${appId}`
        ).then(response => {
            const records = response.records || [];
            LoggingUtils.logOperation(`Found records`, `${records.length} records`);
            return records.map((record) => {
                const recordId = record.$id?.value || 'unknown';
                return new KintoneRecord(appId, recordId, record);
            });
        });
    }

    async createRecord(appId, fields) {
        const params = { app: appId, record: fields };
        return this.executeWithDetailedLogging(
            'createRecord',
            params,
            () => this.client.record.addRecord(params),
            `create record in app ${appId}`
        ).then(response => response.id);
    }

    async updateRecord(record) {
        const params = {
            app: record.appId,
            id: record.recordId,
            record: record.fields
        };
        return this.executeWithDetailedLogging(
            'updateRecord',
            params,
            () => this.client.record.updateRecord(params),
            `update record ${record.appId}/${record.recordId}`
        );
    }

    async updateRecordByKey(appId, keyField, keyValue, fields) {
        const params = {
            app: appId,
            updateKey: {
                field: keyField,
                value: keyValue
            },
            record: fields
        };
        return this.executeWithDetailedLogging(
            'updateRecordByKey',
            params,
            () => this.client.record.updateRecordByUpdateKey(params),
            `update record by key ${appId}/${keyField}=${keyValue}`
        );
    }

    async addRecordComment(appId, recordId, text, mentions = []) {
        const params = {
            app: appId,
            record: recordId,
            comment: {
                text: text,
                mentions: mentions
            }
        };
        return this.executeWithDetailedLogging(
            'addRecordComment',
            params,
            () => this.client.record.addRecordComment(params),
            `add comment to record ${appId}/${recordId}`
        ).then(response => response.id);
    }

    async getRecordAcl(appId, recordIds) {
        // kintone REST APIではレコード単位のアクセス権限取得はサポートされていません
        throw new Error(
            'レコード単位のアクセス権限取得機能はkintone REST APIではサポートされていません。\n\n' +
            '代替案:\n' +
            '1. アプリ全体のアクセス権限を確認する場合は get_app_acl を使用してください\n' +
            '2. プロセス管理のステータスに基づくアクセス制御を確認する場合は get_process_management を使用してください\n' +
            '3. レコードの作成者・更新者を確認する場合は、レコード取得時に CREATOR/MODIFIER フィールドを参照してください'
        );
    }

    async updateRecordStatus(appId, recordId, action, assignee = null) {
        const params = {
            app: appId,
            id: recordId,
            action: action
        };
        
        if (assignee) {
            params.assignee = assignee;
        }
        
        return this.executeWithDetailedLogging(
            'updateRecordStatus',
            params,
            () => this.client.record.updateRecordStatus(params),
            `update record status ${appId}/${recordId}`
        );
    }

    async updateRecordAssignees(appId, recordId, assignees) {
        const params = {
            app: appId,
            id: recordId,
            assignees: assignees
        };
        return this.executeWithDetailedLogging(
            'updateRecordAssignees',
            params,
            () => this.client.record.updateRecordAssignees(params),
            `update record assignees ${appId}/${recordId}`
        );
    }

    async getRecordComments(appId, recordId, order = 'desc', offset = 0, limit = 10) {
        const params = {
            app: appId,
            record: recordId,
            order: order,
            offset: offset,
            limit: limit
        };
        return this.executeWithDetailedLogging(
            'getRecordComments',
            params,
            () => this.client.record.getRecordComments(params),
            `get comments for record ${appId}/${recordId}`
        ).then(response => ({
            comments: response.comments,
            totalCount: response.totalCount
        }));
    }

    async updateRecordComment(appId, recordId, commentId, text, mentions = []) {
        const params = {
            app: appId,
            record: recordId,
            comment: commentId,
            text: text,
            mentions: mentions
        };
        return this.executeWithDetailedLogging(
            'updateRecordComment',
            params,
            () => this.client.record.updateRecordComment(params),
            `update comment ${commentId} for record ${appId}/${recordId}`
        );
    }

    async createRecords(appId, records) {
        const params = {
            app: appId,
            records: records
        };
        return this.executeWithDetailedLogging(
            'createRecords',
            params,
            () => this.client.record.addRecords(params),
            `create records in app ${appId}`
        );
    }

    async updateRecords(appId, records) {
        const params = {
            app: appId,
            records: records
        };
        return this.executeWithDetailedLogging(
            'updateRecords',
            params,
            () => this.client.record.updateRecords(params),
            `update records in app ${appId}`
        );
    }

    async upsertRecord(appId, updateKey, fields) {
        const params = {
            app: appId,
            updateKey: updateKey,
            record: fields
        };
        return this.executeWithDetailedLogging(
            'upsertRecord',
            params,
            () => this.client.record.upsertRecord(params),
            `upsert record in app ${appId} with key ${updateKey.field}=${updateKey.value}`
        );
    }

    async upsertRecords(appId, records) {
        const params = {
            app: appId,
            records: records.map((entry) => ({
                updateKey: entry.updateKey,
                record: entry.fields
            }))
        };

        return this.executeWithDetailedLogging(
            'upsertRecords',
            params,
            () => this.client.record.upsertRecords(params),
            `upsert multiple records in app ${appId}`
        );
    }
}

```

--------------------------------------------------------------------------------
/src/server/tools/RecordTools.js:
--------------------------------------------------------------------------------

```javascript
// src/server/tools/RecordTools.js
import { KintoneRecord } from '../../models/KintoneRecord.js';
import { ValidationUtils } from '../../utils/ValidationUtils.js';
import { LoggingUtils } from '../../utils/LoggingUtils.js';
import { ResponseBuilder } from '../../utils/ResponseBuilder.js';

// レコード関連のツールを処理する関数
export async function handleRecordTools(name, args, repository) {
    // 共通のツール実行ログ
    LoggingUtils.logToolExecution('record', name, args);
    
    switch (name) {
        case 'get_record': {
            ValidationUtils.validateRequired(args, ['app_id', 'record_id']);
            
            const record = await repository.getRecord(args.app_id, args.record_id);
            return record.fields;  // KintoneRecord ではなく fields を返す
        }
        
        case 'search_records': {
            ValidationUtils.validateRequired(args, ['app_id']);
            
            // クエリーが提供されている場合、kintoneクエリー構文を検証
            if (args.query) {
                ValidationUtils.validateKintoneQuery(args.query);
            }
            
            const records = await repository.searchRecords(
                args.app_id,
                args.query,
                args.fields
            );
            return records.map(r => r.fields);
        }
        
        case 'create_record': {
            ValidationUtils.validateRequired(args, ['app_id', 'fields']);
            ValidationUtils.validateObject(args.fields, 'fields');
            
            // フィールドの検証
            if (!args.fields.project_manager) {
                LoggingUtils.logWarning('create_record', 'project_manager field is missing');
            }
            
            const recordId = await repository.createRecord(
                args.app_id,
                args.fields
            );
            return ResponseBuilder.recordCreated(recordId);
        }
        
        case 'update_record': {
            ValidationUtils.validateRequired(args, ['app_id', 'fields']);
            
            // レコードIDまたはupdateKeyのいずれかが必要
            if (!args.record_id && !args.updateKey) {
                throw new Error('record_id または updateKey は必須パラメータです。');
            }
            
            ValidationUtils.validateObject(args.fields, 'fields');
            
            let response;
            if (args.record_id) {
                // レコードIDを使用した更新
                response = await repository.updateRecord(
                    new KintoneRecord(
                        args.app_id,
                        args.record_id,
                        args.fields
                    )
                );
            } else {
                // updateKeyを使用した更新
                response = await repository.updateRecordByKey(
                    args.app_id,
                    args.updateKey.field,
                    args.updateKey.value,
                    args.fields
                );
            }
            
            return ResponseBuilder.recordUpdated(response.revision);
        }
        
        case 'add_record_comment': {
            ValidationUtils.validateRequired(args, ['app_id', 'record_id', 'text']);
            ValidationUtils.validateString(args.text, 'text');
            
            const commentId = await repository.addRecordComment(
                args.app_id,
                args.record_id,
                args.text,
                args.mentions || []
            );
            return ResponseBuilder.withId('comment_id', commentId);
        }
        
        case 'update_record_status': {
            ValidationUtils.validateRequired(args, ['app_id', 'record_id', 'action']);
            ValidationUtils.validateString(args.action, 'action');
            
            const response = await repository.updateRecordStatus(
                args.app_id,
                args.record_id,
                args.action,
                args.assignee
            );
            return ResponseBuilder.withRevision(response.revision);
        }
        
        case 'update_record_assignees': {
            ValidationUtils.validateRequired(args, ['app_id', 'record_id', 'assignees']);
            ValidationUtils.validateArray(args.assignees, 'assignees', {
                maxLength: 100
            });
            
            const response = await repository.updateRecordAssignees(
                args.app_id,
                args.record_id,
                args.assignees
            );
            return ResponseBuilder.withRevision(response.revision);
        }
        
        case 'get_record_comments': {
            ValidationUtils.validateRequired(args, ['app_id', 'record_id']);
            
            const comments = await repository.getRecordComments(
                args.app_id,
                args.record_id,
                args.order || 'desc',
                args.offset || 0,
                args.limit || 10
            );
            return comments;
        }
        
        case 'update_record_comment': {
            ValidationUtils.validateRequired(args, ['app_id', 'record_id', 'comment_id', 'text']);
            ValidationUtils.validateString(args.text, 'text');
            
            await repository.updateRecordComment(
                args.app_id,
                args.record_id,
                args.comment_id,
                args.text,
                args.mentions || []
            );
            return ResponseBuilder.success();
        }
        
        case 'create_records': {
            ValidationUtils.validateRequired(args, ['app_id', 'records']);
            ValidationUtils.validateArray(args.records, 'records', {
                minLength: 1,
                maxLength: 100
            });
            
            const result = await repository.createRecords(args.app_id, args.records);
            return ResponseBuilder.recordsCreated(result.ids, result.revisions);
        }
        
        case 'upsert_record': {
            ValidationUtils.validateRequired(args, ['app_id', 'updateKey', 'fields']);
            ValidationUtils.validateObject(args.updateKey, 'updateKey');
            ValidationUtils.validateString(args.updateKey.field, 'updateKey.field');
            ValidationUtils.validateObject(args.fields, 'fields');
            
            const result = await repository.upsertRecord(
                args.app_id,
                args.updateKey,
                args.fields
            );
            
            // result.id: 作成または更新されたレコードのID
            // result.revision: レコードのリビジョン番号
            return {
                record_id: result.id,
                revision: result.revision,
                message: `レコードをupsertしました (ID: ${result.id})`
            };
        }

        case 'upsert_records': {
            ValidationUtils.validateRequired(args, ['app_id', 'records']);
            ValidationUtils.validateArray(args.records, 'records', {
                minLength: 1,
                maxLength: 100
            });

            const normalizedRecords = args.records.map((entry, index) => {
                ValidationUtils.validateObject(entry, `records[${index}]`);
                ValidationUtils.validateObject(entry.updateKey, `records[${index}].updateKey`);
                ValidationUtils.validateString(entry.updateKey.field, `records[${index}].updateKey.field`);
                if (entry.updateKey.value === undefined || entry.updateKey.value === null) {
                    throw new Error(`records[${index}].updateKey.value は必須です。`);
                }
                ValidationUtils.validateObject(entry.fields, `records[${index}].fields`);

                return {
                    updateKey: {
                        field: entry.updateKey.field,
                        value: entry.updateKey.value
                    },
                    fields: entry.fields
                };
            });

            const result = await repository.upsertRecords(args.app_id, normalizedRecords);
            return ResponseBuilder.recordsUpserted(result, {
                message: `${result.length}件のレコードをupsertしました`
            });
        }

        default:
            throw new Error(`Unknown record tool: ${name}`);
    }
}

```

--------------------------------------------------------------------------------
/src/repositories/KintoneRepository.js:
--------------------------------------------------------------------------------

```javascript
// src/repositories/KintoneRepository.js
import { KintoneRecordRepository } from './KintoneRecordRepository.js';
import { KintoneAppRepository } from './KintoneAppRepository.js';
import { KintoneFileRepository } from './KintoneFileRepository.js';
import { KintoneSpaceRepository } from './KintoneSpaceRepository.js';
import { KintoneUserRepository } from './KintoneUserRepository.js';

export class KintoneRepository {
    constructor(credentials) {
        this.credentials = credentials;
        
        // 各専門リポジトリのインスタンスを作成
        this.recordRepo = new KintoneRecordRepository(credentials);
        this.appRepo = new KintoneAppRepository(credentials);
        this.fileRepo = new KintoneFileRepository(credentials);
        this.spaceRepo = new KintoneSpaceRepository(credentials);
        this.userRepo = new KintoneUserRepository(credentials);
    }

    // プレビュー環境のアプリ設定を取得
    async getPreviewAppSettings(appId, lang) {
        return this.appRepo.getPreviewAppSettings(appId, lang);
    }

    // プレビュー環境のフォームフィールド情報を取得
    async getPreviewFormFields(appId, lang) {
        return this.appRepo.getPreviewFormFields(appId, lang);
    }

    // プレビュー環境のフォームレイアウト情報を取得
    async getPreviewFormLayout(appId) {
        return this.appRepo.getPreviewFormLayout(appId);
    }

    // レコード関連
    async getRecord(appId, recordId) {
        return this.recordRepo.getRecord(appId, recordId);
    }

    async searchRecords(appId, query, fields = []) {
        return this.recordRepo.searchRecords(appId, query, fields);
    }

    async createRecord(appId, fields) {
        return this.recordRepo.createRecord(appId, fields);
    }

    async updateRecord(record) {
        return this.recordRepo.updateRecord(record);
    }

    async addRecordComment(appId, recordId, text, mentions = []) {
        return this.recordRepo.addRecordComment(appId, recordId, text, mentions);
    }

    async getRecordAcl(appId, recordId) {
        return this.appRepo.getRecordAcl(appId, recordId);
    }

    async evaluateRecordsAcl(appId, recordIds) {
        return this.appRepo.evaluateRecordsAcl(appId, recordIds);
    }

    async updateRecordStatus(appId, recordId, action, assignee = null) {
        return this.recordRepo.updateRecordStatus(appId, recordId, action, assignee);
    }

    async updateRecordAssignees(appId, recordId, assignees) {
        return this.recordRepo.updateRecordAssignees(appId, recordId, assignees);
    }

    async getRecordComments(appId, recordId, order = 'desc', offset = 0, limit = 10) {
        return this.recordRepo.getRecordComments(appId, recordId, order, offset, limit);
    }

    async updateRecordComment(appId, recordId, commentId, text, mentions = []) {
        return this.recordRepo.updateRecordComment(appId, recordId, commentId, text, mentions);
    }

    async createRecords(appId, records) {
        return this.recordRepo.createRecords(appId, records);
    }

    async updateRecords(appId, records) {
        return this.recordRepo.updateRecords(appId, records);
    }

    async upsertRecord(appId, updateKey, fields) {
        return this.recordRepo.upsertRecord(appId, updateKey, fields);
    }

    async upsertRecords(appId, records) {
        return this.recordRepo.upsertRecords(appId, records);
    }

    async updateRecordByKey(appId, keyField, keyValue, fields) {
        return this.recordRepo.updateRecordByKey(appId, keyField, keyValue, fields);
    }

    // アプリ関連
    async getAppsInfo(params) {
        return this.appRepo.getAppsInfo(params);
    }

    async createApp(name, space = null, thread = null) {
        return this.appRepo.createApp(name, space, thread);
    }

    async addFields(appId, properties) {
        return this.appRepo.addFields(appId, properties);
    }

    async deployApp(apps) {
        return this.appRepo.deployApp(apps);
    }

    async getDeployStatus(apps) {
        return this.appRepo.getDeployStatus(apps);
    }

    async updateAppSettings(appId, settings) {
        return this.appRepo.updateAppSettings(appId, settings);
    }

    async getFormLayout(appId) {
        return this.appRepo.getFormLayout(appId);
    }

    async getFormFields(appId) {
        return this.appRepo.getFormFields(appId);
    }

    async updateFormLayout(appId, layout, revision = -1) {
        return this.appRepo.updateFormLayout(appId, layout, revision);
    }

    async updateFormFields(appId, properties, revision = -1) {
        return this.appRepo.updateFormFields(appId, properties, revision);
    }

    async deleteFormFields(appId, fields, revision = -1) {
        return this.appRepo.deleteFormFields(appId, fields, revision);
    }

    // ファイル関連
    async uploadFile(fileName, fileData) {
        return this.fileRepo.uploadFile(fileName, fileData);
    }

    async downloadFile(fileKey) {
        return this.fileRepo.downloadFile(fileKey);
    }

    // スペース関連
    async getSpace(spaceId) {
        return this.spaceRepo.getSpace(spaceId);
    }

    async updateSpace(spaceId, settings) {
        return this.spaceRepo.updateSpace(spaceId, settings);
    }

    async updateSpaceBody(spaceId, body) {
        return this.spaceRepo.updateSpaceBody(spaceId, body);
    }

    async getSpaceMembers(spaceId) {
        return this.spaceRepo.getSpaceMembers(spaceId);
    }

    async updateSpaceMembers(spaceId, members) {
        return this.spaceRepo.updateSpaceMembers(spaceId, members);
    }

    async addThread(spaceId, name) {
        return this.spaceRepo.addThread(spaceId, name);
    }

    async updateThread(threadId, params) {
        return this.spaceRepo.updateThread(threadId, params);
    }

    async addThreadComment(spaceId, threadId, comment) {
        return this.spaceRepo.addThreadComment(spaceId, threadId, comment);
    }

    async updateSpaceGuests(spaceId, guests) {
        return this.spaceRepo.updateSpaceGuests(spaceId, guests);
    }

    // アプリをスペースに移動させる
    async moveAppToSpace(appId, spaceId) {
        return this.appRepo.moveAppToSpace(appId, spaceId);
    }

    // アプリをスペースに所属させないようにする
    async moveAppFromSpace(appId) {
        return this.appRepo.moveAppFromSpace(appId);
    }

    // ユーザー関連
    async addGuests(guests) {
        return this.userRepo.addGuests(guests);
    }

    async getUsers(codes = []) {
        return this.userRepo.getUsers(codes);
    }

    async getGroups(codes = []) {
        return this.userRepo.getGroups(codes);
    }

    async getGroupUsers(groupCode) {
        return this.userRepo.getGroupUsers(groupCode);
    }
    
    // アプリのアクション設定を取得
    async getAppActions(appId, lang) {
        return this.appRepo.getAppActions(appId, lang);
    }
    
    // アプリのプラグイン一覧を取得
    async getAppPlugins(appId) {
        return this.appRepo.getAppPlugins(appId);
    }

    // アプリのプロセス管理設定を取得
    async getProcessManagement(appId, preview = false) {
        if (preview) {
            return this.appRepo.previewRepository.getPreviewProcessManagement(appId);
        } else {
            return this.appRepo.getProcessManagement(appId);
        }
    }

    // アプリのプロセス管理設定を更新
    async updateProcessManagement(appId, enable, states, actions, revision = -1) {
        return this.appRepo.updateProcessManagement(appId, enable, states, actions, revision);
    }

    // アプリのビュー設定を取得
    async getViews(appId, preview = false) {
        return this.appRepo.getViews(appId, preview);
    }

    // アプリのビュー設定を更新
    async updateViews(appId, views, revision = -1) {
        return this.appRepo.updateViews(appId, views, revision);
    }

    // アプリのアクセス権限を取得
    async getAppAcl(appId, preview = false) {
        return this.appRepo.getAppAcl(appId, preview);
    }

    // フィールドのアクセス権限を取得
    async getFieldAcl(appId, preview = false) {
        return this.appRepo.getFieldAcl(appId, preview);
    }

    // フィールドのアクセス権限を更新
    async updateFieldAcl(appId, rights, revision = -1) {
        return this.appRepo.updateFieldAcl(appId, rights, revision);
    }

    // グラフ設定を取得
    async getReports(appId, preview = false) {
        return this.appRepo.getReports(appId, preview);
    }

    // グラフ設定を更新
    async updateReports(appId, reports, revision = -1) {
        return this.appRepo.updateReports(appId, reports, revision);
    }

    // 通知条件設定を取得
    async getNotifications(appId, preview = false) {
        return this.appRepo.getNotifications(appId, preview);
    }

    // 通知条件設定を更新
    async updateNotifications(appId, notifications, revision = -1) {
        return this.appRepo.updateNotifications(appId, notifications, revision);
    }

    // レコード単位の通知設定を取得
    async getPerRecordNotifications(appId, preview = false) {
        return this.appRepo.getPerRecordNotifications(appId, preview);
    }

    // レコード単位の通知設定を更新
    async updatePerRecordNotifications(appId, notifications, revision = -1) {
        return this.appRepo.updatePerRecordNotifications(appId, notifications, revision);
    }

    // リマインダー通知設定を取得
    async getReminderNotifications(appId, preview = false) {
        return this.appRepo.getReminderNotifications(appId, preview);
    }

    // リマインダー通知設定を更新
    async updateReminderNotifications(appId, notifications, revision = -1) {
        return this.appRepo.updateReminderNotifications(appId, notifications, revision);
    }

    // アプリアクション設定を更新
    async updateAppActions(appId, actions, revision = -1) {
        return this.appRepo.updateAppActions(appId, actions, revision);
    }

    // プラグイン設定を更新
    async updatePlugins(appId, plugins, revision = -1) {
        return this.appRepo.updatePlugins(appId, plugins, revision);
    }

    // JavaScript/CSSカスタマイズ設定を取得
    async getAppCustomize(appId, preview = false) {
        return this.appRepo.getAppCustomize(appId, preview);
    }

    // JavaScript/CSSカスタマイズ設定を更新
    async updateAppCustomize(appId, scope, desktop, mobile, revision = -1) {
        return this.appRepo.updateAppCustomize(appId, scope, desktop, mobile, revision);
    }

    // アプリのアクセス権限を更新
    async updateAppAcl(appId, rights, revision = -1) {
        return this.appRepo.updateAppAcl(appId, rights, revision);
    }
}

```

--------------------------------------------------------------------------------
/src/repositories/base/http/createKintoneClient.js:
--------------------------------------------------------------------------------

```javascript
// src/repositories/base/http/createKintoneClient.js
import { KintoneHttpClient } from './KintoneHttpClient.js';

function removePreview(params = {}) {
    const { preview, ...rest } = params;
    return { preview: preview === true, params: rest };
}

export function createKintoneClient(credentials) {
    const http = new KintoneHttpClient(credentials);

    const space = {
        getSpace: (params) => http.get('space', params),
        updateSpace: (params) => http.put('space', params),
        updateSpaceBody: (params) => http.put('space/body', params),
        getSpaceMembers: (params) => http.get('space/members', params),
        updateSpaceMembers: (params) => http.put('space/members', params),
        addThread: (params) => http.post('space/thread', params),
        updateThread: (params) => http.put('space/thread', params),
        addThreadComment: (params) => http.post('space/thread/comment', params),
        updateSpaceGuests: (params) => http.put('space/guests', params),
        addGuests: (params) => http.post('guests', params)
    };

    const app = {
        getApps: (params) => http.get('apps', params),
        addApp: async (params) => {
            const payload = { name: params.name };
            if (params.space) {
                payload.space = params.space;
                if (params.thread) {
                    payload.thread = params.thread;
                } else {
                    const spaceInfo = await space.getSpace({ id: params.space });
                    if (spaceInfo && spaceInfo.defaultThread) {
                        payload.thread = spaceInfo.defaultThread;
                    }
                }
            } else if (params.thread) {
                payload.thread = params.thread;
            }
            return http.post('app', payload, { preview: true });
        },
        deployApp: (params) => http.post('app/deploy', params, { preview: true }),
        getDeployStatus: (params) => http.get('app/deploy', params, { preview: true }),
        getAppSettings: (params = {}) => {
            const { preview, params: rest } = removePreview(params);
            return http.get('app/settings', rest, { preview });
        },
        updateAppSettings: (params) => http.put('app/settings', params, { preview: true }),
        getProcessManagement: (params = {}) => {
            const { preview, params: rest } = removePreview(params);
            return http.get('app/status', rest, { preview });
        },
        updateProcessManagement: (params) => http.put('app/status', params, { preview: true }),
        getFormFields: (params = {}) => {
            const { preview, params: rest } = removePreview(params);
            return http.get('app/form/fields', rest, { preview });
        },
        addFormFields: (params) => http.post('app/form/fields', params, { preview: true }),
        updateFormFields: (params) => http.put('app/form/fields', params, { preview: true }),
        deleteFormFields: (params) => http.delete('app/form/fields', params, { preview: true }),
        getFormLayout: (params = {}) => {
            const { preview, params: rest } = removePreview(params);
            return http.get('app/form/layout', rest, { preview });
        },
        updateFormLayout: (params) => http.put('app/form/layout', params, { preview: true }),
        getViews: (params = {}) => {
            const { preview, params: rest } = removePreview(params);
            return http.get('app/views', rest, { preview });
        },
        updateViews: (params) => http.put('app/views', params, { preview: true }),
        getAppAcl: (params = {}) => {
            const { preview, params: rest } = removePreview(params);
            return http.get('app/acl', rest, { preview });
        },
        updateAppAcl: (params) => http.put('app/acl', params, { preview: true }),
        getFieldAcl: (params = {}) => {
            const { preview, params: rest } = removePreview(params);
            return http.get('field/acl', rest, { preview });
        },
        updateFieldAcl: (params) => http.put('field/acl', params, { preview: true }),
        getAppActions: (params = {}) => {
            const { preview, params: rest } = removePreview(params);
            return http.get('app/actions', rest, { preview });
        },
        updateAppActions: (params) => http.put('app/actions', params, { preview: true }),
        getPlugins: (params = {}) => {
            const { preview, params: rest } = removePreview(params);
            return http.get('app/plugins', rest, { preview });
        },
        updatePlugins: (params) => http.put('app/plugins', params, { preview: true }),
        getReports: (params = {}) => {
            const { preview, params: rest } = removePreview(params);
            return http.get('app/reports', rest, { preview });
        },
        updateReports: (params) => http.put('app/reports', params, { preview: true }),
        getGeneralNotifications: (params = {}) => {
            const { preview, params: rest } = removePreview(params);
            return http.get('app/notifications/general', rest, { preview });
        },
        updateGeneralNotifications: (params) => http.put('app/notifications/general', params, { preview: true }),
        getPerRecordNotifications: (params = {}) => {
            const { preview, params: rest } = removePreview(params);
            return http.get('app/notifications/perRecord', rest, { preview });
        },
        updatePerRecordNotifications: (params) => http.put('app/notifications/perRecord', params, { preview: true }),
        getReminderNotifications: (params = {}) => {
            const { preview, params: rest } = removePreview(params);
            return http.get('app/notifications/reminder', rest, { preview });
        },
        updateReminderNotifications: (params) => http.put('app/notifications/reminder', params, { preview: true }),
        getAppCustomize: (params = {}) => {
            const { preview, params: rest } = removePreview(params);
            return http.get('app/customize', rest, { preview });
        },
        updateAppCustomize: (params) => http.put('app/customize', params, { preview: true }),
        getRecordAcl: (params = {}) => {
            const { preview, params: rest } = removePreview(params);
            return http.get('record/acl', rest, { preview });
        },
        evaluateRecordsAcl: (params) => http.get('records/acl/evaluate', params),
        move: (params) => http.post('app/move', params)
    };

    const record = {
        getRecord: (params) => http.get('record', params),
        addRecord: (params) => http.post('record', params),
        updateRecord: (params) => http.put('record', params),
        updateRecordByUpdateKey: (params) => http.put('record', params),
        getRecords: (params) => http.get('records', params),
        addRecords: (params) => http.post('records', params),
        updateRecords: (params) => http.put('records', params),
        upsertRecord: async (params) => {
            const { app: appId, updateKey, record: recordData } = params;
            const response = await http.put('records', {
                app: appId,
                upsert: true,
                records: [
                    {
                        updateKey,
                        record: recordData
                    }
                ]
            });

            if (!response || !Array.isArray(response.records) || response.records.length === 0) {
                throw new Error('Unexpected response format from records upsert operation.');
            }

            const result = response.records[0];
            return {
                id: result.id,
                revision: result.revision,
                operation: result.operation
            };
        },
        upsertRecords: async (params) => {
            const { app: appId, records } = params;
            if (!Array.isArray(records) || records.length === 0) {
                throw new Error('records must be a non-empty array when calling upsertRecords.');
            }

            const formattedRecords = records.map((entry) => ({
                updateKey: entry.updateKey,
                record: entry.record
            }));

            const response = await http.put('records', {
                app: appId,
                upsert: true,
                records: formattedRecords
            });

            if (!response || !Array.isArray(response.records) || response.records.length === 0) {
                throw new Error('Unexpected response format from records upsert operation.');
            }

            return response.records.map((recordResult) => ({
                id: recordResult.id,
                revision: recordResult.revision,
                operation: recordResult.operation
            }));
        },
        addRecordComment: (params) => http.post('record/comment', params),
        getRecordComments: (params) => http.get('record/comments', params),
        updateRecordComment: (params) => http.put('record/comment', params),
        updateRecordStatus: (params) => http.put('record/status', params),
        updateRecordAssignees: (params) => http.put('record/assignees', params)
    };

    const file = {
        uploadFile: async (params) => {
            const form = new FormData();
            const fileData = params.file?.data;
            const fileName = params.file?.name;

            if (fileData === undefined || fileData === null) {
                throw new Error('Missing file data for upload.');
            }

            const blob = fileData instanceof Blob ? fileData : new Blob([fileData]);
            form.append('file', blob, fileName ?? 'upload.bin');
            return http.post('file', form);
        },
        downloadFile: async (params) => {
            const response = await http.get('file', params, {
                responseType: 'arraybuffer',
                rawResponse: true
            });
            const contentType = response.headers['content-type'] || response.headers['Content-Type'];
            return {
                data: response.data,
                contentType
            };
        }
    };

    return { app, record, space, file };
}

```

--------------------------------------------------------------------------------
/docs/mcp-specification/2024-11-05.txt:
--------------------------------------------------------------------------------

```
└── docs
    └── specification
        └── 2024-11-05
            ├── _index.md
            ├── architecture
                └── _index.md
            ├── basic
                ├── _index.md
                ├── lifecycle.md
                ├── messages.md
                ├── transports.md
                └── utilities
                │   ├── _index.md
                │   ├── cancellation.md
                │   ├── ping.md
                │   └── progress.md
            ├── client
                ├── _index.md
                ├── roots.md
                └── sampling.md
            └── server
                ├── _index.md
                ├── prompts.md
                ├── resource-picker.png
                ├── resources.md
                ├── slash-command.png
                ├── tools.md
                └── utilities
                    ├── _index.md
                    ├── completion.md
                    ├── logging.md
                    └── pagination.md


/docs/specification/2024-11-05/_index.md:
--------------------------------------------------------------------------------
  1 | ---
  2 | linkTitle: 2024-11-05 (Final)
  3 | title: Model Context Protocol specification
  4 | cascade:
  5 |   type: docs
  6 | breadcrumbs: false
  7 | weight: 2
  8 | ---
  9 | 
 10 | {{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}
 11 | 
 12 | [Model Context Protocol](https://modelcontextprotocol.io) (MCP) is an open protocol that
 13 | enables seamless integration between LLM applications and external data sources and
 14 | tools. Whether you're building an AI-powered IDE, enhancing a chat interface, or creating
 15 | custom AI workflows, MCP provides a standardized way to connect LLMs with the context
 16 | they need.
 17 | 
 18 | This specification defines the authoritative protocol requirements, based on the
 19 | TypeScript schema in
 20 | [schema.ts](https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.ts).
 21 | 
 22 | For implementation guides and examples, visit
 23 | [modelcontextprotocol.io](https://modelcontextprotocol.io).
 24 | 
 25 | The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD
 26 | NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be
 27 | interpreted as described in [BCP 14](https://datatracker.ietf.org/doc/html/bcp14)
 28 | [[RFC2119](https://datatracker.ietf.org/doc/html/rfc2119)]
 29 | [[RFC8174](https://datatracker.ietf.org/doc/html/rfc8174)] when, and only when, they
 30 | appear in all capitals, as shown here.
 31 | 
 32 | ## Overview
 33 | 
 34 | MCP provides a standardized way for applications to:
 35 | 
 36 | - Share contextual information with language models
 37 | - Expose tools and capabilities to AI systems
 38 | - Build composable integrations and workflows
 39 | 
 40 | The protocol uses [JSON-RPC](https://www.jsonrpc.org/) 2.0 messages to establish
 41 | communication between:
 42 | 
 43 | - **Hosts**: LLM applications that initiate connections
 44 | - **Clients**: Connectors within the host application
 45 | - **Servers**: Services that provide context and capabilities
 46 | 
 47 | MCP takes some inspiration from the
 48 | [Language Server Protocol](https://microsoft.github.io/language-server-protocol/), which
 49 | standardizes how to add support for programming languages across a whole ecosystem of
 50 | development tools. In a similar way, MCP standardizes how to integrate additional context
 51 | and tools into the ecosystem of AI applications.
 52 | 
 53 | ## Key Details
 54 | 
 55 | ### Base Protocol
 56 | 
 57 | - [JSON-RPC](https://www.jsonrpc.org/) message format
 58 | - Stateful connections
 59 | - Server and client capability negotiation
 60 | 
 61 | ### Features
 62 | 
 63 | Servers offer any of the following features to clients:
 64 | 
 65 | - **Resources**: Context and data, for the user or the AI model to use
 66 | - **Prompts**: Templated messages and workflows for users
 67 | - **Tools**: Functions for the AI model to execute
 68 | 
 69 | Clients may offer the following feature to servers:
 70 | 
 71 | - **Sampling**: Server-initiated agentic behaviors and recursive LLM interactions
 72 | 
 73 | ### Additional Utilities
 74 | 
 75 | - Configuration
 76 | - Progress tracking
 77 | - Cancellation
 78 | - Error reporting
 79 | - Logging
 80 | 
 81 | ## Security and Trust & Safety
 82 | 
 83 | The Model Context Protocol enables powerful capabilities through arbitrary data access
 84 | and code execution paths. With this power comes important security and trust
 85 | considerations that all implementors must carefully address.
 86 | 
 87 | ### Key Principles
 88 | 
 89 | 1. **User Consent and Control**
 90 | 
 91 |    - Users must explicitly consent to and understand all data access and operations
 92 |    - Users must retain control over what data is shared and what actions are taken
 93 |    - Implementors should provide clear UIs for reviewing and authorizing activities
 94 | 
 95 | 2. **Data Privacy**
 96 | 
 97 |    - Hosts must obtain explicit user consent before exposing user data to servers
 98 |    - Hosts must not transmit resource data elsewhere without user consent
 99 |    - User data should be protected with appropriate access controls
100 | 
101 | 3. **Tool Safety**
102 | 
103 |    - Tools represent arbitrary code execution and must be treated with appropriate
104 |      caution
105 |    - Hosts must obtain explicit user consent before invoking any tool
106 |    - Users should understand what each tool does before authorizing its use
107 | 
108 | 4. **LLM Sampling Controls**
109 |    - Users must explicitly approve any LLM sampling requests
110 |    - Users should control:
111 |      - Whether sampling occurs at all
112 |      - The actual prompt that will be sent
113 |      - What results the server can see
114 |    - The protocol intentionally limits server visibility into prompts
115 | 
116 | ### Implementation Guidelines
117 | 
118 | While MCP itself cannot enforce these security principles at the protocol level,
119 | implementors **SHOULD**:
120 | 
121 | 1. Build robust consent and authorization flows into their applications
122 | 2. Provide clear documentation of security implications
123 | 3. Implement appropriate access controls and data protections
124 | 4. Follow security best practices in their integrations
125 | 5. Consider privacy implications in their feature designs
126 | 
127 | ## Learn More
128 | 
129 | Explore the detailed specification for each protocol component:
130 | 
131 | {{< cards >}} {{< card link="architecture" title="Architecture" icon="template" >}}
132 | {{< card link="basic" title="Base Protocol" icon="code" >}}
133 | {{< card link="server" title="Server Features" icon="server" >}}
134 | {{< card link="client" title="Client Features" icon="user" >}}
135 | {{< card link="contributing" title="Contributing" icon="pencil" >}} {{< /cards >}}
136 | 


--------------------------------------------------------------------------------
/docs/specification/2024-11-05/architecture/_index.md:
--------------------------------------------------------------------------------
  1 | ---
  2 | title: Architecture
  3 | cascade:
  4 |   type: docs
  5 | weight: 1
  6 | ---
  7 | 
  8 | The Model Context Protocol (MCP) follows a client-host-server architecture where each
  9 | host can run multiple client instances. This architecture enables users to integrate AI
 10 | capabilities across applications while maintaining clear security boundaries and
 11 | isolating concerns. Built on JSON-RPC, MCP provides a stateful session protocol focused
 12 | on context exchange and sampling coordination between clients and servers.
 13 | 
 14 | ## Core Components
 15 | 
 16 | ```mermaid
 17 | graph LR
 18 |     subgraph "Application Host Process"
 19 |         H[Host]
 20 |         C1[Client 1]
 21 |         C2[Client 2]
 22 |         C3[Client 3]
 23 |         H --> C1
 24 |         H --> C2
 25 |         H --> C3
 26 |     end
 27 | 
 28 |     subgraph "Local machine"
 29 |         S1[Server 1<br>Files & Git]
 30 |         S2[Server 2<br>Database]
 31 |         R1[("Local<br>Resource A")]
 32 |         R2[("Local<br>Resource B")]
 33 | 
 34 |         C1 --> S1
 35 |         C2 --> S2
 36 |         S1 <--> R1
 37 |         S2 <--> R2
 38 |     end
 39 | 
 40 |     subgraph "Internet"
 41 |         S3[Server 3<br>External APIs]
 42 |         R3[("Remote<br>Resource C")]
 43 | 
 44 |         C3 --> S3
 45 |         S3 <--> R3
 46 |     end
 47 | ```
 48 | 
 49 | ### Host
 50 | 
 51 | The host process acts as the container and coordinator:
 52 | 
 53 | - Creates and manages multiple client instances
 54 | - Controls client connection permissions and lifecycle
 55 | - Enforces security policies and consent requirements
 56 | - Handles user authorization decisions
 57 | - Coordinates AI/LLM integration and sampling
 58 | - Manages context aggregation across clients
 59 | 
 60 | ### Clients
 61 | 
 62 | Each client is created by the host and maintains an isolated server connection:
 63 | 
 64 | - Establishes one stateful session per server
 65 | - Handles protocol negotiation and capability exchange
 66 | - Routes protocol messages bidirectionally
 67 | - Manages subscriptions and notifications
 68 | - Maintains security boundaries between servers
 69 | 
 70 | A host application creates and manages multiple clients, with each client having a 1:1
 71 | relationship with a particular server.
 72 | 
 73 | ### Servers
 74 | 
 75 | Servers provide specialized context and capabilities:
 76 | 
 77 | - Expose resources, tools and prompts via MCP primitives
 78 | - Operate independently with focused responsibilities
 79 | - Request sampling through client interfaces
 80 | - Must respect security constraints
 81 | - Can be local processes or remote services
 82 | 
 83 | ## Design Principles
 84 | 
 85 | MCP is built on several key design principles that inform its architecture and
 86 | implementation:
 87 | 
 88 | 1. **Servers should be extremely easy to build**
 89 | 
 90 |    - Host applications handle complex orchestration responsibilities
 91 |    - Servers focus on specific, well-defined capabilities
 92 |    - Simple interfaces minimize implementation overhead
 93 |    - Clear separation enables maintainable code
 94 | 
 95 | 2. **Servers should be highly composable**
 96 | 
 97 |    - Each server provides focused functionality in isolation
 98 |    - Multiple servers can be combined seamlessly
 99 |    - Shared protocol enables interoperability
100 |    - Modular design supports extensibility
101 | 
102 | 3. **Servers should not be able to read the whole conversation, nor "see into" other
103 |    servers**
104 | 
105 |    - Servers receive only necessary contextual information
106 |    - Full conversation history stays with the host
107 |    - Each server connection maintains isolation
108 |    - Cross-server interactions are controlled by the host
109 |    - Host process enforces security boundaries
110 | 
111 | 4. **Features can be added to servers and clients progressively**
112 |    - Core protocol provides minimal required functionality
113 |    - Additional capabilities can be negotiated as needed
114 |    - Servers and clients evolve independently
115 |    - Protocol designed for future extensibility
116 |    - Backwards compatibility is maintained
117 | 
118 | ## Message Types
119 | 
120 | MCP defines three core message types based on
121 | [JSON-RPC 2.0](https://www.jsonrpc.org/specification):
122 | 
123 | - **Requests**: Bidirectional messages with method and parameters expecting a response
124 | - **Responses**: Successful results or errors matching specific request IDs
125 | - **Notifications**: One-way messages requiring no response
126 | 
127 | Each message type follows the JSON-RPC 2.0 specification for structure and delivery
128 | semantics.
129 | 
130 | ## Capability Negotiation
131 | 
132 | The Model Context Protocol uses a capability-based negotiation system where clients and
133 | servers explicitly declare their supported features during initialization. Capabilities
134 | determine which protocol features and primitives are available during a session.
135 | 
136 | - Servers declare capabilities like resource subscriptions, tool support, and prompt
137 |   templates
138 | - Clients declare capabilities like sampling support and notification handling
139 | - Both parties must respect declared capabilities throughout the session
140 | - Additional capabilities can be negotiated through extensions to the protocol
141 | 
142 | ```mermaid
143 | sequenceDiagram
144 |     participant Host
145 |     participant Client
146 |     participant Server
147 | 
148 |     Host->>+Client: Initialize client
149 |     Client->>+Server: Initialize session with capabilities
150 |     Server-->>Client: Respond with supported capabilities
151 | 
152 |     Note over Host,Server: Active Session with Negotiated Features
153 | 
154 |     loop Client Requests
155 |         Host->>Client: User- or model-initiated action
156 |         Client->>Server: Request (tools/resources)
157 |         Server-->>Client: Response
158 |         Client-->>Host: Update UI or respond to model
159 |     end
160 | 
161 |     loop Server Requests
162 |         Server->>Client: Request (sampling)
163 |         Client->>Host: Forward to AI
164 |         Host-->>Client: AI response
165 |         Client-->>Server: Response
166 |     end
167 | 
168 |     loop Notifications
169 |         Server--)Client: Resource updates
170 |         Client--)Server: Status changes
171 |     end
172 | 
173 |     Host->>Client: Terminate
174 |     Client->>-Server: End session
175 |     deactivate Server
176 | ```
177 | 
178 | Each capability unlocks specific protocol features for use during the session. For
179 | example:
180 | 
181 | - Implemented [server features]({{< ref "/specification/2024-11-05/server" >}}) must be
182 |   advertised in the server's capabilities
183 | - Emitting resource subscription notifications requires the server to declare
184 |   subscription support
185 | - Tool invocation requires the server to declare tool capabilities
186 | - [Sampling]({{< ref "/specification/2024-11-05/client" >}}) requires the client to
187 |   declare support in its capabilities
188 | 
189 | This capability negotiation ensures clients and servers have a clear understanding of
190 | supported functionality while maintaining protocol extensibility.
191 | 


--------------------------------------------------------------------------------
/docs/specification/2024-11-05/basic/_index.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | title: Base Protocol
 3 | cascade:
 4 |   type: docs
 5 | weight: 2
 6 | ---
 7 | 
 8 | {{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}
 9 | 
10 | All messages between MCP clients and servers **MUST** follow the
11 | [JSON-RPC 2.0](https://www.jsonrpc.org/specification) specification. The protocol defines
12 | three fundamental types of messages:
13 | 
14 | | Type            | Description                            | Requirements                           |
15 | | --------------- | -------------------------------------- | -------------------------------------- |
16 | | `Requests`      | Messages sent to initiate an operation | Must include unique ID and method name |
17 | | `Responses`     | Messages sent in reply to requests     | Must include same ID as request        |
18 | | `Notifications` | One-way messages with no reply         | Must not include an ID                 |
19 | 
20 | **Responses** are further sub-categorized as either **successful results** or **errors**.
21 | Results can follow any JSON object structure, while errors must include an error code and
22 | message at minimum.
23 | 
24 | ## Protocol Layers
25 | 
26 | The Model Context Protocol consists of several key components that work together:
27 | 
28 | - **Base Protocol**: Core JSON-RPC message types
29 | - **Lifecycle Management**: Connection initialization, capability negotiation, and
30 |   session control
31 | - **Server Features**: Resources, prompts, and tools exposed by servers
32 | - **Client Features**: Sampling and root directory lists provided by clients
33 | - **Utilities**: Cross-cutting concerns like logging and argument completion
34 | 
35 | All implementations **MUST** support the base protocol and lifecycle management
36 | components. Other components **MAY** be implemented based on the specific needs of the
37 | application.
38 | 
39 | These protocol layers establish clear separation of concerns while enabling rich
40 | interactions between clients and servers. The modular design allows implementations to
41 | support exactly the features they need.
42 | 
43 | See the following pages for more details on the different components:
44 | 
45 | {{< cards >}}
46 | {{< card link="/specification/2024-11-05/basic/lifecycle" title="Lifecycle" icon="refresh" >}}
47 | {{< card link="/specification/2024-11-05/server/resources" title="Resources" icon="document" >}}
48 | {{< card link="/specification/2024-11-05/server/prompts" title="Prompts" icon="chat-alt-2" >}}
49 | {{< card link="/specification/2024-11-05/server/tools" title="Tools" icon="adjustments" >}}
50 | {{< card link="/specification/2024-11-05/server/utilities/logging" title="Logging" icon="annotation" >}}
51 | {{< card link="/specification/2024-11-05/client/sampling" title="Sampling" icon="code" >}}
52 | {{< /cards >}}
53 | 
54 | ## Auth
55 | 
56 | Authentication and authorization are not currently part of the core MCP specification,
57 | but we are considering ways to introduce them in future. Join us in
58 | [GitHub Discussions](https://github.com/modelcontextprotocol/specification/discussions)
59 | to help shape the future of the protocol!
60 | 
61 | Clients and servers **MAY** negotiate their own custom authentication and authorization
62 | strategies.
63 | 
64 | ## Schema
65 | 
66 | The full specification of the protocol is defined as a
67 | [TypeScript schema](http://github.com/modelcontextprotocol/specification/tree/main/schema/2024-11-05/schema.ts).
68 | This is the source of truth for all protocol messages and structures.
69 | 
70 | There is also a
71 | [JSON Schema](http://github.com/modelcontextprotocol/specification/tree/main/schema/2024-11-05/schema.json),
72 | which is automatically generated from the TypeScript source of truth, for use with
73 | various automated tooling.
74 | 


--------------------------------------------------------------------------------
/docs/specification/2024-11-05/basic/lifecycle.md:
--------------------------------------------------------------------------------
  1 | ---
  2 | title: Lifecycle
  3 | type: docs
  4 | weight: 30
  5 | ---
  6 | 
  7 | {{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}
  8 | 
  9 | The Model Context Protocol (MCP) defines a rigorous lifecycle for client-server
 10 | connections that ensures proper capability negotiation and state management.
 11 | 
 12 | 1. **Initialization**: Capability negotiation and protocol version agreement
 13 | 2. **Operation**: Normal protocol communication
 14 | 3. **Shutdown**: Graceful termination of the connection
 15 | 
 16 | ```mermaid
 17 | sequenceDiagram
 18 |     participant Client
 19 |     participant Server
 20 | 
 21 |     Note over Client,Server: Initialization Phase
 22 |     activate Client
 23 |     Client->>+Server: initialize request
 24 |     Server-->>Client: initialize response
 25 |     Client--)Server: initialized notification
 26 | 
 27 |     Note over Client,Server: Operation Phase
 28 |     rect rgb(200, 220, 250)
 29 |         note over Client,Server: Normal protocol operations
 30 |     end
 31 | 
 32 |     Note over Client,Server: Shutdown
 33 |     Client--)-Server: Disconnect
 34 |     deactivate Server
 35 |     Note over Client,Server: Connection closed
 36 | ```
 37 | 
 38 | ## Lifecycle Phases
 39 | 
 40 | ### Initialization
 41 | 
 42 | The initialization phase **MUST** be the first interaction between client and server.
 43 | During this phase, the client and server:
 44 | 
 45 | - Establish protocol version compatibility
 46 | - Exchange and negotiate capabilities
 47 | - Share implementation details
 48 | 
 49 | The client **MUST** initiate this phase by sending an `initialize` request containing:
 50 | 
 51 | - Protocol version supported
 52 | - Client capabilities
 53 | - Client implementation information
 54 | 
 55 | ```json
 56 | {
 57 |   "jsonrpc": "2.0",
 58 |   "id": 1,
 59 |   "method": "initialize",
 60 |   "params": {
 61 |     "protocolVersion": "2024-11-05",
 62 |     "capabilities": {
 63 |       "roots": {
 64 |         "listChanged": true
 65 |       },
 66 |       "sampling": {}
 67 |     },
 68 |     "clientInfo": {
 69 |       "name": "ExampleClient",
 70 |       "version": "1.0.0"
 71 |     }
 72 |   }
 73 | }
 74 | ```
 75 | 
 76 | The server **MUST** respond with its own capabilities and information:
 77 | 
 78 | ```json
 79 | {
 80 |   "jsonrpc": "2.0",
 81 |   "id": 1,
 82 |   "result": {
 83 |     "protocolVersion": "2024-11-05",
 84 |     "capabilities": {
 85 |       "logging": {},
 86 |       "prompts": {
 87 |         "listChanged": true
 88 |       },
 89 |       "resources": {
 90 |         "subscribe": true,
 91 |         "listChanged": true
 92 |       },
 93 |       "tools": {
 94 |         "listChanged": true
 95 |       }
 96 |     },
 97 |     "serverInfo": {
 98 |       "name": "ExampleServer",
 99 |       "version": "1.0.0"
100 |     }
101 |   }
102 | }
103 | ```
104 | 
105 | After successful initialization, the client **MUST** send an `initialized` notification
106 | to indicate it is ready to begin normal operations:
107 | 
108 | ```json
109 | {
110 |   "jsonrpc": "2.0",
111 |   "method": "notifications/initialized"
112 | }
113 | ```
114 | 
115 | - The client **SHOULD NOT** send requests other than
116 |   [pings]({{< ref "/specification/2024-11-05/basic/utilities/ping" >}}) before the server
117 |   has responded to the `initialize` request.
118 | - The server **SHOULD NOT** send requests other than
119 |   [pings]({{< ref "/specification/2024-11-05/basic/utilities/ping" >}}) and
120 |   [logging]({{< ref "/specification/2024-11-05/server/utilities/logging" >}}) before
121 |   receiving the `initialized` notification.
122 | 
123 | #### Version Negotiation
124 | 
125 | In the `initialize` request, the client **MUST** send a protocol version it supports.
126 | This **SHOULD** be the _latest_ version supported by the client.
127 | 
128 | If the server supports the requested protocol version, it **MUST** respond with the same
129 | version. Otherwise, the server **MUST** respond with another protocol version it
130 | supports. This **SHOULD** be the _latest_ version supported by the server.
131 | 
132 | If the client does not support the version in the server's response, it **SHOULD**
133 | disconnect.
134 | 
135 | #### Capability Negotiation
136 | 
137 | Client and server capabilities establish which optional protocol features will be
138 | available during the session.
139 | 
140 | Key capabilities include:
141 | 
142 | | Category | Capability     | Description                                                                                       |
143 | | -------- | -------------- | ------------------------------------------------------------------------------------------------- |
144 | | Client   | `roots`        | Ability to provide filesystem [roots]({{< ref "/specification/2024-11-05/client/roots" >}})       |
145 | | Client   | `sampling`     | Support for LLM [sampling]({{< ref "/specification/2024-11-05/client/sampling" >}}) requests      |
146 | | Client   | `experimental` | Describes support for non-standard experimental features                                          |
147 | | Server   | `prompts`      | Offers [prompt templates]({{< ref "/specification/2024-11-05/server/prompts" >}})                 |
148 | | Server   | `resources`    | Provides readable [resources]({{< ref "/specification/2024-11-05/server/resources" >}})           |
149 | | Server   | `tools`        | Exposes callable [tools]({{< ref "/specification/2024-11-05/server/tools" >}})                    |
150 | | Server   | `logging`      | Emits structured [log messages]({{< ref "/specification/2024-11-05/server/utilities/logging" >}}) |
151 | | Server   | `experimental` | Describes support for non-standard experimental features                                          |
152 | 
153 | Capability objects can describe sub-capabilities like:
154 | 
155 | - `listChanged`: Support for list change notifications (for prompts, resources, and
156 |   tools)
157 | - `subscribe`: Support for subscribing to individual items' changes (resources only)
158 | 
159 | ### Operation
160 | 
161 | During the operation phase, the client and server exchange messages according to the
162 | negotiated capabilities.
163 | 
164 | Both parties **SHOULD**:
165 | 
166 | - Respect the negotiated protocol version
167 | - Only use capabilities that were successfully negotiated
168 | 
169 | ### Shutdown
170 | 
171 | During the shutdown phase, one side (usually the client) cleanly terminates the protocol
172 | connection. No specific shutdown messages are defined—instead, the underlying transport
173 | mechanism should be used to signal connection termination:
174 | 
175 | #### stdio
176 | 
177 | For the stdio [transport]({{< ref "/specification/2024-11-05/basic/transports" >}}), the
178 | client **SHOULD** initiate shutdown by:
179 | 
180 | 1. First, closing the input stream to the child process (the server)
181 | 2. Waiting for the server to exit, or sending `SIGTERM` if the server does not exit
182 |    within a reasonable time
183 | 3. Sending `SIGKILL` if the server does not exit within a reasonable time after `SIGTERM`
184 | 
185 | The server **MAY** initiate shutdown by closing its output stream to the client and
186 | exiting.
187 | 
188 | #### HTTP
189 | 
190 | For HTTP [transports]({{< ref "/specification/2024-11-05/basic/transports" >}}), shutdown
191 | is indicated by closing the associated HTTP connection(s).
192 | 
193 | ## Error Handling
194 | 
195 | Implementations **SHOULD** be prepared to handle these error cases:
196 | 
197 | - Protocol version mismatch
198 | - Failure to negotiate required capabilities
199 | - Initialize request timeout
200 | - Shutdown timeout
201 | 
202 | Implementations **SHOULD** implement appropriate timeouts for all requests, to prevent
203 | hung connections and resource exhaustion.
204 | 
205 | Example initialization error:
206 | 
207 | ```json
208 | {
209 |   "jsonrpc": "2.0",
210 |   "id": 1,
211 |   "error": {
212 |     "code": -32602,
213 |     "message": "Unsupported protocol version",
214 |     "data": {
215 |       "supported": ["2024-11-05"],
216 |       "requested": "1.0.0"
217 |     }
218 |   }
219 | }
220 | ```
221 | 


--------------------------------------------------------------------------------
/docs/specification/2024-11-05/basic/messages.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | title: Messages
 3 | type: docs
 4 | weight: 20
 5 | ---
 6 | 
 7 | {{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}
 8 | 
 9 | All messages in MCP **MUST** follow the
10 | [JSON-RPC 2.0](https://www.jsonrpc.org/specification) specification. The protocol defines
11 | three types of messages:
12 | 
13 | ## Requests
14 | 
15 | Requests are sent from the client to the server or vice versa.
16 | 
17 | ```typescript
18 | {
19 |   jsonrpc: "2.0";
20 |   id: string | number;
21 |   method: string;
22 |   params?: {
23 |     [key: string]: unknown;
24 |   };
25 | }
26 | ```
27 | 
28 | - Requests **MUST** include a string or integer ID.
29 | - Unlike base JSON-RPC, the ID **MUST NOT** be `null`.
30 | - The request ID **MUST NOT** have been previously used by the requestor within the same
31 |   session.
32 | 
33 | ## Responses
34 | 
35 | Responses are sent in reply to requests.
36 | 
37 | ```typescript
38 | {
39 |   jsonrpc: "2.0";
40 |   id: string | number;
41 |   result?: {
42 |     [key: string]: unknown;
43 |   }
44 |   error?: {
45 |     code: number;
46 |     message: string;
47 |     data?: unknown;
48 |   }
49 | }
50 | ```
51 | 
52 | - Responses **MUST** include the same ID as the request they correspond to.
53 | - Either a `result` or an `error` **MUST** be set. A response **MUST NOT** set both.
54 | - Error codes **MUST** be integers.
55 | 
56 | ## Notifications
57 | 
58 | Notifications are sent from the client to the server or vice versa. They do not expect a
59 | response.
60 | 
61 | ```typescript
62 | {
63 |   jsonrpc: "2.0";
64 |   method: string;
65 |   params?: {
66 |     [key: string]: unknown;
67 |   };
68 | }
69 | ```
70 | 
71 | - Notifications **MUST NOT** include an ID.
72 | 


--------------------------------------------------------------------------------
/docs/specification/2024-11-05/basic/transports.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | title: Transports
 3 | type: docs
 4 | weight: 40
 5 | ---
 6 | 
 7 | {{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}
 8 | 
 9 | MCP currently defines two standard transport mechanisms for client-server communication:
10 | 
11 | 1. [stdio](#stdio), communication over standard in and standard out
12 | 2. [HTTP with Server-Sent Events](#http-with-sse) (SSE)
13 | 
14 | Clients **SHOULD** support stdio whenever possible.
15 | 
16 | It is also possible for clients and servers to implement
17 | [custom transports](#custom-transports) in a pluggable fashion.
18 | 
19 | ## stdio
20 | 
21 | In the **stdio** transport:
22 | 
23 | - The client launches the MCP server as a subprocess.
24 | - The server receives JSON-RPC messages on its standard input (`stdin`) and writes
25 |   responses to its standard output (`stdout`).
26 | - Messages are delimited by newlines, and **MUST NOT** contain embedded newlines.
27 | - The server **MAY** write UTF-8 strings to its standard error (`stderr`) for logging
28 |   purposes. Clients **MAY** capture, forward, or ignore this logging.
29 | - The server **MUST NOT** write anything to its `stdout` that is not a valid MCP message.
30 | - The client **MUST NOT** write anything to the server's `stdin` that is not a valid MCP
31 |   message.
32 | 
33 | ```mermaid
34 | sequenceDiagram
35 |     participant Client
36 |     participant Server Process
37 | 
38 |     Client->>+Server Process: Launch subprocess
39 |     loop Message Exchange
40 |         Client->>Server Process: Write to stdin
41 |         Server Process->>Client: Write to stdout
42 |         Server Process--)Client: Optional logs on stderr
43 |     end
44 |     Client->>Server Process: Close stdin, terminate subprocess
45 |     deactivate Server Process
46 | ```
47 | 
48 | ## HTTP with SSE
49 | 
50 | In the **SSE** transport, the server operates as an independent process that can handle
51 | multiple client connections.
52 | 
53 | The server **MUST** provide two endpoints:
54 | 
55 | 1. An SSE endpoint, for clients to establish a connection and receive messages from the
56 |    server
57 | 2. A regular HTTP POST endpoint for clients to send messages to the server
58 | 
59 | When a client connects, the server **MUST** send an `endpoint` event containing a URI for
60 | the client to use for sending messages. All subsequent client messages **MUST** be sent
61 | as HTTP POST requests to this endpoint.
62 | 
63 | Server messages are sent as SSE `message` events, with the message content encoded as
64 | JSON in the event data.
65 | 
66 | ```mermaid
67 | sequenceDiagram
68 |     participant Client
69 |     participant Server
70 | 
71 |     Client->>Server: Open SSE connection
72 |     Server->>Client: endpoint event
73 |     loop Message Exchange
74 |         Client->>Server: HTTP POST messages
75 |         Server->>Client: SSE message events
76 |     end
77 |     Client->>Server: Close SSE connection
78 | ```
79 | 
80 | ## Custom Transports
81 | 
82 | Clients and servers **MAY** implement additional custom transport mechanisms to suit
83 | their specific needs. The protocol is transport-agnostic and can be implemented over any
84 | communication channel that supports bidirectional message exchange.
85 | 
86 | Implementers who choose to support custom transports **MUST** ensure they preserve the
87 | JSON-RPC message format and lifecycle requirements defined by MCP. Custom transports
88 | **SHOULD** document their specific connection establishment and message exchange patterns
89 | to aid interoperability.
90 | 


--------------------------------------------------------------------------------
/docs/specification/2024-11-05/basic/utilities/_index.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | title: Utilities
 3 | ---
 4 | 
 5 | {{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}
 6 | 
 7 | These optional features enhance the base protocol functionality with various utilities.
 8 | 
 9 | {{< cards >}} {{< card link="ping" title="Ping" icon="status-online" >}}
10 | {{< card link="cancellation" title="Cancellation" icon="x" >}}
11 | {{< card link="progress" title="Progress" icon="clock" >}} {{< /cards >}}
12 | 


--------------------------------------------------------------------------------
/docs/specification/2024-11-05/basic/utilities/cancellation.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | title: Cancellation
 3 | weight: 10
 4 | ---
 5 | 
 6 | {{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}
 7 | 
 8 | The Model Context Protocol (MCP) supports optional cancellation of in-progress requests
 9 | through notification messages. Either side can send a cancellation notification to
10 | indicate that a previously-issued request should be terminated.
11 | 
12 | ## Cancellation Flow
13 | 
14 | When a party wants to cancel an in-progress request, it sends a `notifications/cancelled`
15 | notification containing:
16 | 
17 | - The ID of the request to cancel
18 | - An optional reason string that can be logged or displayed
19 | 
20 | ```json
21 | {
22 |   "jsonrpc": "2.0",
23 |   "method": "notifications/cancelled",
24 |   "params": {
25 |     "requestId": "123",
26 |     "reason": "User requested cancellation"
27 |   }
28 | }
29 | ```
30 | 
31 | ## Behavior Requirements
32 | 
33 | 1. Cancellation notifications **MUST** only reference requests that:
34 |    - Were previously issued in the same direction
35 |    - Are believed to still be in-progress
36 | 2. The `initialize` request **MUST NOT** be cancelled by clients
37 | 3. Receivers of cancellation notifications **SHOULD**:
38 |    - Stop processing the cancelled request
39 |    - Free associated resources
40 |    - Not send a response for the cancelled request
41 | 4. Receivers **MAY** ignore cancellation notifications if:
42 |    - The referenced request is unknown
43 |    - Processing has already completed
44 |    - The request cannot be cancelled
45 | 5. The sender of the cancellation notification **SHOULD** ignore any response to the
46 |    request that arrives afterward
47 | 
48 | ## Timing Considerations
49 | 
50 | Due to network latency, cancellation notifications may arrive after request processing
51 | has completed, and potentially after a response has already been sent.
52 | 
53 | Both parties **MUST** handle these race conditions gracefully:
54 | 
55 | ```mermaid
56 | sequenceDiagram
57 |    participant Client
58 |    participant Server
59 | 
60 |    Client->>Server: Request (ID: 123)
61 |    Note over Server: Processing starts
62 |    Client--)Server: notifications/cancelled (ID: 123)
63 |    alt
64 |       Note over Server: Processing may have<br/>completed before<br/>cancellation arrives
65 |    else If not completed
66 |       Note over Server: Stop processing
67 |    end
68 | ```
69 | 
70 | ## Implementation Notes
71 | 
72 | - Both parties **SHOULD** log cancellation reasons for debugging
73 | - Application UIs **SHOULD** indicate when cancellation is requested
74 | 
75 | ## Error Handling
76 | 
77 | Invalid cancellation notifications **SHOULD** be ignored:
78 | 
79 | - Unknown request IDs
80 | - Already completed requests
81 | - Malformed notifications
82 | 
83 | This maintains the "fire and forget" nature of notifications while allowing for race
84 | conditions in asynchronous communication.
85 | 


--------------------------------------------------------------------------------
/docs/specification/2024-11-05/basic/utilities/ping.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | title: Ping
 3 | weight: 5
 4 | ---
 5 | 
 6 | {{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}
 7 | 
 8 | The Model Context Protocol includes an optional ping mechanism that allows either party
 9 | to verify that their counterpart is still responsive and the connection is alive.
10 | 
11 | ## Overview
12 | 
13 | The ping functionality is implemented through a simple request/response pattern. Either
14 | the client or server can initiate a ping by sending a `ping` request.
15 | 
16 | ## Message Format
17 | 
18 | A ping request is a standard JSON-RPC request with no parameters:
19 | 
20 | ```json
21 | {
22 |   "jsonrpc": "2.0",
23 |   "id": "123",
24 |   "method": "ping"
25 | }
26 | ```
27 | 
28 | ## Behavior Requirements
29 | 
30 | 1. The receiver **MUST** respond promptly with an empty response:
31 | 
32 | ```json
33 | {
34 |   "jsonrpc": "2.0",
35 |   "id": "123",
36 |   "result": {}
37 | }
38 | ```
39 | 
40 | 2. If no response is received within a reasonable timeout period, the sender **MAY**:
41 |    - Consider the connection stale
42 |    - Terminate the connection
43 |    - Attempt reconnection procedures
44 | 
45 | ## Usage Patterns
46 | 
47 | ```mermaid
48 | sequenceDiagram
49 |     participant Sender
50 |     participant Receiver
51 | 
52 |     Sender->>Receiver: ping request
53 |     Receiver->>Sender: empty response
54 | ```
55 | 
56 | ## Implementation Considerations
57 | 
58 | - Implementations **SHOULD** periodically issue pings to detect connection health
59 | - The frequency of pings **SHOULD** be configurable
60 | - Timeouts **SHOULD** be appropriate for the network environment
61 | - Excessive pinging **SHOULD** be avoided to reduce network overhead
62 | 
63 | ## Error Handling
64 | 
65 | - Timeouts **SHOULD** be treated as connection failures
66 | - Multiple failed pings **MAY** trigger connection reset
67 | - Implementations **SHOULD** log ping failures for diagnostics
68 | 


--------------------------------------------------------------------------------
/docs/specification/2024-11-05/basic/utilities/progress.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | title: Progress
 3 | weight: 30
 4 | ---
 5 | 
 6 | {{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}
 7 | 
 8 | The Model Context Protocol (MCP) supports optional progress tracking for long-running
 9 | operations through notification messages. Either side can send progress notifications to
10 | provide updates about operation status.
11 | 
12 | ## Progress Flow
13 | 
14 | When a party wants to _receive_ progress updates for a request, it includes a
15 | `progressToken` in the request metadata.
16 | 
17 | - Progress tokens **MUST** be a string or integer value
18 | - Progress tokens can be chosen by the sender using any means, but **MUST** be unique
19 |   across all active requests.
20 | 
21 | ```json
22 | {
23 |   "jsonrpc": "2.0",
24 |   "id": 1,
25 |   "method": "some_method",
26 |   "params": {
27 |     "_meta": {
28 |       "progressToken": "abc123"
29 |     }
30 |   }
31 | }
32 | ```
33 | 
34 | The receiver **MAY** then send progress notifications containing:
35 | 
36 | - The original progress token
37 | - The current progress value so far
38 | - An optional "total" value
39 | 
40 | ```json
41 | {
42 |   "jsonrpc": "2.0",
43 |   "method": "notifications/progress",
44 |   "params": {
45 |     "progressToken": "abc123",
46 |     "progress": 50,
47 |     "total": 100
48 |   }
49 | }
50 | ```
51 | 
52 | - The `progress` value **MUST** increase with each notification, even if the total is
53 |   unknown.
54 | - The `progress` and the `total` values **MAY** be floating point.
55 | 
56 | ## Behavior Requirements
57 | 
58 | 1. Progress notifications **MUST** only reference tokens that:
59 | 
60 |    - Were provided in an active request
61 |    - Are associated with an in-progress operation
62 | 
63 | 2. Receivers of progress requests **MAY**:
64 |    - Choose not to send any progress notifications
65 |    - Send notifications at whatever frequency they deem appropriate
66 |    - Omit the total value if unknown
67 | 
68 | ```mermaid
69 | sequenceDiagram
70 |     participant Sender
71 |     participant Receiver
72 | 
73 |     Note over Sender,Receiver: Request with progress token
74 |     Sender->>Receiver: Method request with progressToken
75 | 
76 |     Note over Sender,Receiver: Progress updates
77 |     loop Progress Updates
78 |         Receiver-->>Sender: Progress notification (0.2/1.0)
79 |         Receiver-->>Sender: Progress notification (0.6/1.0)
80 |         Receiver-->>Sender: Progress notification (1.0/1.0)
81 |     end
82 | 
83 |     Note over Sender,Receiver: Operation complete
84 |     Receiver->>Sender: Method response
85 | ```
86 | 
87 | ## Implementation Notes
88 | 
89 | - Senders and receivers **SHOULD** track active progress tokens
90 | - Both parties **SHOULD** implement rate limiting to prevent flooding
91 | - Progress notifications **MUST** stop after completion
92 | 


--------------------------------------------------------------------------------
/docs/specification/2024-11-05/client/_index.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | title: Client Features
 3 | cascade:
 4 |   type: docs
 5 | weight: 4
 6 | ---
 7 | 
 8 | {{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}
 9 | 
10 | Clients can implement additional features to enrich connected MCP servers:
11 | 
12 | {{< cards >}} {{< card link="roots" title="Roots" icon="folder" >}}
13 | {{< card link="sampling" title="Sampling" icon="annotation" >}} {{< /cards >}}
14 | 


--------------------------------------------------------------------------------
/docs/specification/2024-11-05/client/roots.md:
--------------------------------------------------------------------------------
  1 | ---
  2 | title: Roots
  3 | type: docs
  4 | weight: 40
  5 | ---
  6 | 
  7 | {{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}
  8 | 
  9 | The Model Context Protocol (MCP) provides a standardized way for clients to expose
 10 | filesystem "roots" to servers. Roots define the boundaries of where servers can operate
 11 | within the filesystem, allowing them to understand which directories and files they have
 12 | access to. Servers can request the list of roots from supporting clients and receive
 13 | notifications when that list changes.
 14 | 
 15 | ## User Interaction Model
 16 | 
 17 | Roots in MCP are typically exposed through workspace or project configuration interfaces.
 18 | 
 19 | For example, implementations could offer a workspace/project picker that allows users to
 20 | select directories and files the server should have access to. This can be combined with
 21 | automatic workspace detection from version control systems or project files.
 22 | 
 23 | However, implementations are free to expose roots through any interface pattern that
 24 | suits their needs&mdash;the protocol itself does not mandate any specific user
 25 | interaction model.
 26 | 
 27 | ## Capabilities
 28 | 
 29 | Clients that support roots **MUST** declare the `roots` capability during
 30 | [initialization]({{< ref "/specification/2024-11-05/basic/lifecycle#initialization" >}}):
 31 | 
 32 | ```json
 33 | {
 34 |   "capabilities": {
 35 |     "roots": {
 36 |       "listChanged": true
 37 |     }
 38 |   }
 39 | }
 40 | ```
 41 | 
 42 | `listChanged` indicates whether the client will emit notifications when the list of roots
 43 | changes.
 44 | 
 45 | ## Protocol Messages
 46 | 
 47 | ### Listing Roots
 48 | 
 49 | To retrieve roots, servers send a `roots/list` request:
 50 | 
 51 | **Request:**
 52 | 
 53 | ```json
 54 | {
 55 |   "jsonrpc": "2.0",
 56 |   "id": 1,
 57 |   "method": "roots/list"
 58 | }
 59 | ```
 60 | 
 61 | **Response:**
 62 | 
 63 | ```json
 64 | {
 65 |   "jsonrpc": "2.0",
 66 |   "id": 1,
 67 |   "result": {
 68 |     "roots": [
 69 |       {
 70 |         "uri": "file:///home/user/projects/myproject",
 71 |         "name": "My Project"
 72 |       }
 73 |     ]
 74 |   }
 75 | }
 76 | ```
 77 | 
 78 | ### Root List Changes
 79 | 
 80 | When roots change, clients that support `listChanged` **MUST** send a notification:
 81 | 
 82 | ```json
 83 | {
 84 |   "jsonrpc": "2.0",
 85 |   "method": "notifications/roots/list_changed"
 86 | }
 87 | ```
 88 | 
 89 | ## Message Flow
 90 | 
 91 | ```mermaid
 92 | sequenceDiagram
 93 |     participant Server
 94 |     participant Client
 95 | 
 96 |     Note over Server,Client: Discovery
 97 |     Server->>Client: roots/list
 98 |     Client-->>Server: Available roots
 99 | 
100 |     Note over Server,Client: Changes
101 |     Client--)Server: notifications/roots/list_changed
102 |     Server->>Client: roots/list
103 |     Client-->>Server: Updated roots
104 | ```
105 | 
106 | ## Data Types
107 | 
108 | ### Root
109 | 
110 | A root definition includes:
111 | 
112 | - `uri`: Unique identifier for the root. This **MUST** be a `file://` URI in the current
113 |   specification.
114 | - `name`: Optional human-readable name for display purposes.
115 | 
116 | Example roots for different use cases:
117 | 
118 | #### Project Directory
119 | 
120 | ```json
121 | {
122 |   "uri": "file:///home/user/projects/myproject",
123 |   "name": "My Project"
124 | }
125 | ```
126 | 
127 | #### Multiple Repositories
128 | 
129 | ```json
130 | [
131 |   {
132 |     "uri": "file:///home/user/repos/frontend",
133 |     "name": "Frontend Repository"
134 |   },
135 |   {
136 |     "uri": "file:///home/user/repos/backend",
137 |     "name": "Backend Repository"
138 |   }
139 | ]
140 | ```
141 | 
142 | ## Error Handling
143 | 
144 | Clients **SHOULD** return standard JSON-RPC errors for common failure cases:
145 | 
146 | - Client does not support roots: `-32601` (Method not found)
147 | - Internal errors: `-32603`
148 | 
149 | Example error:
150 | 
151 | ```json
152 | {
153 |   "jsonrpc": "2.0",
154 |   "id": 1,
155 |   "error": {
156 |     "code": -32601,
157 |     "message": "Roots not supported",
158 |     "data": {
159 |       "reason": "Client does not have roots capability"
160 |     }
161 |   }
162 | }
163 | ```
164 | 
165 | ## Security Considerations
166 | 
167 | 1. Clients **MUST**:
168 | 
169 |    - Only expose roots with appropriate permissions
170 |    - Validate all root URIs to prevent path traversal
171 |    - Implement proper access controls
172 |    - Monitor root accessibility
173 | 
174 | 2. Servers **SHOULD**:
175 |    - Handle cases where roots become unavailable
176 |    - Respect root boundaries during operations
177 |    - Validate all paths against provided roots
178 | 
179 | ## Implementation Guidelines
180 | 
181 | 1. Clients **SHOULD**:
182 | 
183 |    - Prompt users for consent before exposing roots to servers
184 |    - Provide clear user interfaces for root management
185 |    - Validate root accessibility before exposing
186 |    - Monitor for root changes
187 | 
188 | 2. Servers **SHOULD**:
189 |    - Check for roots capability before usage
190 |    - Handle root list changes gracefully
191 |    - Respect root boundaries in operations
192 |    - Cache root information appropriately
193 | 


--------------------------------------------------------------------------------
/docs/specification/2024-11-05/client/sampling.md:
--------------------------------------------------------------------------------
  1 | ---
  2 | title: Sampling
  3 | type: docs
  4 | weight: 40
  5 | ---
  6 | 
  7 | {{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}
  8 | 
  9 | The Model Context Protocol (MCP) provides a standardized way for servers to request LLM
 10 | sampling ("completions" or "generations") from language models via clients. This flow
 11 | allows clients to maintain control over model access, selection, and permissions while
 12 | enabling servers to leverage AI capabilities&mdash;with no server API keys necessary.
 13 | Servers can request text or image-based interactions and optionally include context from
 14 | MCP servers in their prompts.
 15 | 
 16 | ## User Interaction Model
 17 | 
 18 | Sampling in MCP allows servers to implement agentic behaviors, by enabling LLM calls to
 19 | occur _nested_ inside other MCP server features.
 20 | 
 21 | Implementations are free to expose sampling through any interface pattern that suits
 22 | their needs&mdash;the protocol itself does not mandate any specific user interaction
 23 | model.
 24 | 
 25 | {{< callout type="warning" >}} For trust & safety and security, there **SHOULD** always
 26 | be a human in the loop with the ability to deny sampling requests.
 27 | 
 28 | Applications **SHOULD**:
 29 | 
 30 | - Provide UI that makes it easy and intuitive to review sampling requests
 31 | - Allow users to view and edit prompts before sending
 32 | - Present generated responses for review before delivery {{< /callout >}}
 33 | 
 34 | ## Capabilities
 35 | 
 36 | Clients that support sampling **MUST** declare the `sampling` capability during
 37 | [initialization]({{< ref "/specification/2024-11-05/basic/lifecycle#initialization" >}}):
 38 | 
 39 | ```json
 40 | {
 41 |   "capabilities": {
 42 |     "sampling": {}
 43 |   }
 44 | }
 45 | ```
 46 | 
 47 | ## Protocol Messages
 48 | 
 49 | ### Creating Messages
 50 | 
 51 | To request a language model generation, servers send a `sampling/createMessage` request:
 52 | 
 53 | **Request:**
 54 | 
 55 | ```json
 56 | {
 57 |   "jsonrpc": "2.0",
 58 |   "id": 1,
 59 |   "method": "sampling/createMessage",
 60 |   "params": {
 61 |     "messages": [
 62 |       {
 63 |         "role": "user",
 64 |         "content": {
 65 |           "type": "text",
 66 |           "text": "What is the capital of France?"
 67 |         }
 68 |       }
 69 |     ],
 70 |     "modelPreferences": {
 71 |       "hints": [
 72 |         {
 73 |           "name": "claude-3-sonnet"
 74 |         }
 75 |       ],
 76 |       "intelligencePriority": 0.8,
 77 |       "speedPriority": 0.5
 78 |     },
 79 |     "systemPrompt": "You are a helpful assistant.",
 80 |     "maxTokens": 100
 81 |   }
 82 | }
 83 | ```
 84 | 
 85 | **Response:**
 86 | 
 87 | ```json
 88 | {
 89 |   "jsonrpc": "2.0",
 90 |   "id": 1,
 91 |   "result": {
 92 |     "role": "assistant",
 93 |     "content": {
 94 |       "type": "text",
 95 |       "text": "The capital of France is Paris."
 96 |     },
 97 |     "model": "claude-3-sonnet-20240307",
 98 |     "stopReason": "endTurn"
 99 |   }
100 | }
101 | ```
102 | 
103 | ## Message Flow
104 | 
105 | ```mermaid
106 | sequenceDiagram
107 |     participant Server
108 |     participant Client
109 |     participant User
110 |     participant LLM
111 | 
112 |     Note over Server,Client: Server initiates sampling
113 |     Server->>Client: sampling/createMessage
114 | 
115 |     Note over Client,User: Human-in-the-loop review
116 |     Client->>User: Present request for approval
117 |     User-->>Client: Review and approve/modify
118 | 
119 |     Note over Client,LLM: Model interaction
120 |     Client->>LLM: Forward approved request
121 |     LLM-->>Client: Return generation
122 | 
123 |     Note over Client,User: Response review
124 |     Client->>User: Present response for approval
125 |     User-->>Client: Review and approve/modify
126 | 
127 |     Note over Server,Client: Complete request
128 |     Client-->>Server: Return approved response
129 | ```
130 | 
131 | ## Data Types
132 | 
133 | ### Messages
134 | 
135 | Sampling messages can contain:
136 | 
137 | #### Text Content
138 | 
139 | ```json
140 | {
141 |   "type": "text",
142 |   "text": "The message content"
143 | }
144 | ```
145 | 
146 | #### Image Content
147 | 
148 | ```json
149 | {
150 |   "type": "image",
151 |   "data": "base64-encoded-image-data",
152 |   "mimeType": "image/jpeg"
153 | }
154 | ```
155 | 
156 | ### Model Preferences
157 | 
158 | Model selection in MCP requires careful abstraction since servers and clients may use
159 | different AI providers with distinct model offerings. A server cannot simply request a
160 | specific model by name since the client may not have access to that exact model or may
161 | prefer to use a different provider's equivalent model.
162 | 
163 | To solve this, MCP implements a preference system that combines abstract capability
164 | priorities with optional model hints:
165 | 
166 | #### Capability Priorities
167 | 
168 | Servers express their needs through three normalized priority values (0-1):
169 | 
170 | - `costPriority`: How important is minimizing costs? Higher values prefer cheaper models.
171 | - `speedPriority`: How important is low latency? Higher values prefer faster models.
172 | - `intelligencePriority`: How important are advanced capabilities? Higher values prefer
173 |   more capable models.
174 | 
175 | #### Model Hints
176 | 
177 | While priorities help select models based on characteristics, `hints` allow servers to
178 | suggest specific models or model families:
179 | 
180 | - Hints are treated as substrings that can match model names flexibly
181 | - Multiple hints are evaluated in order of preference
182 | - Clients **MAY** map hints to equivalent models from different providers
183 | - Hints are advisory&mdash;clients make final model selection
184 | 
185 | For example:
186 | 
187 | ```json
188 | {
189 |   "hints": [
190 |     { "name": "claude-3-sonnet" }, // Prefer Sonnet-class models
191 |     { "name": "claude" } // Fall back to any Claude model
192 |   ],
193 |   "costPriority": 0.3, // Cost is less important
194 |   "speedPriority": 0.8, // Speed is very important
195 |   "intelligencePriority": 0.5 // Moderate capability needs
196 | }
197 | ```
198 | 
199 | The client processes these preferences to select an appropriate model from its available
200 | options. For instance, if the client doesn't have access to Claude models but has Gemini,
201 | it might map the sonnet hint to `gemini-1.5-pro` based on similar capabilities.
202 | 
203 | ## Error Handling
204 | 
205 | Clients **SHOULD** return errors for common failure cases:
206 | 
207 | Example error:
208 | 
209 | ```json
210 | {
211 |   "jsonrpc": "2.0",
212 |   "id": 1,
213 |   "error": {
214 |     "code": -1,
215 |     "message": "User rejected sampling request"
216 |   }
217 | }
218 | ```
219 | 
220 | ## Security Considerations
221 | 
222 | 1. Clients **SHOULD** implement user approval controls
223 | 2. Both parties **SHOULD** validate message content
224 | 3. Clients **SHOULD** respect model preference hints
225 | 4. Clients **SHOULD** implement rate limiting
226 | 5. Both parties **MUST** handle sensitive data appropriately
227 | 


--------------------------------------------------------------------------------
/docs/specification/2024-11-05/server/_index.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | title: Server Features
 3 | cascade:
 4 |   type: docs
 5 | weight: 3
 6 | ---
 7 | 
 8 | {{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}
 9 | 
10 | Servers provide the fundamental building blocks for adding context to language models via
11 | MCP. These primitives enable rich interactions between clients, servers, and language
12 | models:
13 | 
14 | - **Prompts**: Pre-defined templates or instructions that guide language model
15 |   interactions
16 | - **Resources**: Structured data or content that provides additional context to the model
17 | - **Tools**: Executable functions that allow models to perform actions or retrieve
18 |   information
19 | 
20 | Each primitive can be summarized in the following control hierarchy:
21 | 
22 | | Primitive | Control                | Description                                        | Example                         |
23 | | --------- | ---------------------- | -------------------------------------------------- | ------------------------------- |
24 | | Prompts   | User-controlled        | Interactive templates invoked by user choice       | Slash commands, menu options    |
25 | | Resources | Application-controlled | Contextual data attached and managed by the client | File contents, git history      |
26 | | Tools     | Model-controlled       | Functions exposed to the LLM to take actions       | API POST requests, file writing |
27 | 
28 | Explore these key primitives in more detail below:
29 | 
30 | {{< cards >}} {{< card link="prompts" title="Prompts" icon="chat-alt-2" >}}
31 | {{< card link="resources" title="Resources" icon="document" >}}
32 | {{< card link="tools" title="Tools" icon="adjustments" >}} {{< /cards >}}
33 | 


--------------------------------------------------------------------------------
/docs/specification/2024-11-05/server/prompts.md:
--------------------------------------------------------------------------------
  1 | ---
  2 | title: Prompts
  3 | weight: 10
  4 | ---
  5 | 
  6 | {{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}
  7 | 
  8 | The Model Context Protocol (MCP) provides a standardized way for servers to expose prompt
  9 | templates to clients. Prompts allow servers to provide structured messages and
 10 | instructions for interacting with language models. Clients can discover available
 11 | prompts, retrieve their contents, and provide arguments to customize them.
 12 | 
 13 | ## User Interaction Model
 14 | 
 15 | Prompts are designed to be **user-controlled**, meaning they are exposed from servers to
 16 | clients with the intention of the user being able to explicitly select them for use.
 17 | 
 18 | Typically, prompts would be triggered through user-initiated commands in the user
 19 | interface, which allows users to naturally discover and invoke available prompts.
 20 | 
 21 | For example, as slash commands:
 22 | 
 23 | ![Example of prompt exposed as slash command](slash-command.png)
 24 | 
 25 | However, implementors are free to expose prompts through any interface pattern that suits
 26 | their needs&mdash;the protocol itself does not mandate any specific user interaction
 27 | model.
 28 | 
 29 | ## Capabilities
 30 | 
 31 | Servers that support prompts **MUST** declare the `prompts` capability during
 32 | [initialization]({{< ref "/specification/2024-11-05/basic/lifecycle#initialization" >}}):
 33 | 
 34 | ```json
 35 | {
 36 |   "capabilities": {
 37 |     "prompts": {
 38 |       "listChanged": true
 39 |     }
 40 |   }
 41 | }
 42 | ```
 43 | 
 44 | `listChanged` indicates whether the server will emit notifications when the list of
 45 | available prompts changes.
 46 | 
 47 | ## Protocol Messages
 48 | 
 49 | ### Listing Prompts
 50 | 
 51 | To retrieve available prompts, clients send a `prompts/list` request. This operation
 52 | supports
 53 | [pagination]({{< ref "/specification/2024-11-05/server/utilities/pagination" >}}).
 54 | 
 55 | **Request:**
 56 | 
 57 | ```json
 58 | {
 59 |   "jsonrpc": "2.0",
 60 |   "id": 1,
 61 |   "method": "prompts/list",
 62 |   "params": {
 63 |     "cursor": "optional-cursor-value"
 64 |   }
 65 | }
 66 | ```
 67 | 
 68 | **Response:**
 69 | 
 70 | ```json
 71 | {
 72 |   "jsonrpc": "2.0",
 73 |   "id": 1,
 74 |   "result": {
 75 |     "prompts": [
 76 |       {
 77 |         "name": "code_review",
 78 |         "description": "Asks the LLM to analyze code quality and suggest improvements",
 79 |         "arguments": [
 80 |           {
 81 |             "name": "code",
 82 |             "description": "The code to review",
 83 |             "required": true
 84 |           }
 85 |         ]
 86 |       }
 87 |     ],
 88 |     "nextCursor": "next-page-cursor"
 89 |   }
 90 | }
 91 | ```
 92 | 
 93 | ### Getting a Prompt
 94 | 
 95 | To retrieve a specific prompt, clients send a `prompts/get` request. Arguments may be
 96 | auto-completed through [the completion
 97 | API]({{< ref "/specification/2024-11-05/server/utilities/completion" >}}).
 98 | 
 99 | **Request:**
100 | 
101 | ```json
102 | {
103 |   "jsonrpc": "2.0",
104 |   "id": 2,
105 |   "method": "prompts/get",
106 |   "params": {
107 |     "name": "code_review",
108 |     "arguments": {
109 |       "code": "def hello():\n    print('world')"
110 |     }
111 |   }
112 | }
113 | ```
114 | 
115 | **Response:**
116 | 
117 | ```json
118 | {
119 |   "jsonrpc": "2.0",
120 |   "id": 2,
121 |   "result": {
122 |     "description": "Code review prompt",
123 |     "messages": [
124 |       {
125 |         "role": "user",
126 |         "content": {
127 |           "type": "text",
128 |           "text": "Please review this Python code:\ndef hello():\n    print('world')"
129 |         }
130 |       }
131 |     ]
132 |   }
133 | }
134 | ```
135 | 
136 | ### List Changed Notification
137 | 
138 | When the list of available prompts changes, servers that declared the `listChanged`
139 | capability **SHOULD** send a notification:
140 | 
141 | ```json
142 | {
143 |   "jsonrpc": "2.0",
144 |   "method": "notifications/prompts/list_changed"
145 | }
146 | ```
147 | 
148 | ## Message Flow
149 | 
150 | ```mermaid
151 | sequenceDiagram
152 |     participant Client
153 |     participant Server
154 | 
155 |     Note over Client,Server: Discovery
156 |     Client->>Server: prompts/list
157 |     Server-->>Client: List of prompts
158 | 
159 |     Note over Client,Server: Usage
160 |     Client->>Server: prompts/get
161 |     Server-->>Client: Prompt content
162 | 
163 |     opt listChanged
164 |       Note over Client,Server: Changes
165 |       Server--)Client: prompts/list_changed
166 |       Client->>Server: prompts/list
167 |       Server-->>Client: Updated prompts
168 |     end
169 | ```
170 | 
171 | ## Data Types
172 | 
173 | ### Prompt
174 | 
175 | A prompt definition includes:
176 | 
177 | - `name`: Unique identifier for the prompt
178 | - `description`: Optional human-readable description
179 | - `arguments`: Optional list of arguments for customization
180 | 
181 | ### PromptMessage
182 | 
183 | Messages in a prompt can contain:
184 | 
185 | - `role`: Either "user" or "assistant" to indicate the speaker
186 | - `content`: One of the following content types:
187 | 
188 | #### Text Content
189 | 
190 | Text content represents plain text messages:
191 | 
192 | ```json
193 | {
194 |   "type": "text",
195 |   "text": "The text content of the message"
196 | }
197 | ```
198 | 
199 | This is the most common content type used for natural language interactions.
200 | 
201 | #### Image Content
202 | 
203 | Image content allows including visual information in messages:
204 | 
205 | ```json
206 | {
207 |   "type": "image",
208 |   "data": "base64-encoded-image-data",
209 |   "mimeType": "image/png"
210 | }
211 | ```
212 | 
213 | The image data **MUST** be base64-encoded and include a valid MIME type. This enables
214 | multi-modal interactions where visual context is important.
215 | 
216 | #### Embedded Resources
217 | 
218 | Embedded resources allow referencing server-side resources directly in messages:
219 | 
220 | ```json
221 | {
222 |   "type": "resource",
223 |   "resource": {
224 |     "uri": "resource://example",
225 |     "mimeType": "text/plain",
226 |     "text": "Resource content"
227 |   }
228 | }
229 | ```
230 | 
231 | Resources can contain either text or binary (blob) data and **MUST** include:
232 | 
233 | - A valid resource URI
234 | - The appropriate MIME type
235 | - Either text content or base64-encoded blob data
236 | 
237 | Embedded resources enable prompts to seamlessly incorporate server-managed content like
238 | documentation, code samples, or other reference materials directly into the conversation
239 | flow.
240 | 
241 | ## Error Handling
242 | 
243 | Servers **SHOULD** return standard JSON-RPC errors for common failure cases:
244 | 
245 | - Invalid prompt name: `-32602` (Invalid params)
246 | - Missing required arguments: `-32602` (Invalid params)
247 | - Internal errors: `-32603` (Internal error)
248 | 
249 | ## Implementation Considerations
250 | 
251 | 1. Servers **SHOULD** validate prompt arguments before processing
252 | 2. Clients **SHOULD** handle pagination for large prompt lists
253 | 3. Both parties **SHOULD** respect capability negotiation
254 | 
255 | ## Security
256 | 
257 | Implementations **MUST** carefully validate all prompt inputs and outputs to prevent
258 | injection attacks or unauthorized access to resources.
259 | 


--------------------------------------------------------------------------------
/docs/specification/2024-11-05/server/resource-picker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/modelcontextprotocol/specification/main/docs/specification/2024-11-05/server/resource-picker.png


--------------------------------------------------------------------------------
/docs/specification/2024-11-05/server/resources.md:
--------------------------------------------------------------------------------
  1 | ---
  2 | title: Resources
  3 | type: docs
  4 | weight: 20
  5 | ---
  6 | 
  7 | {{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}
  8 | 
  9 | The Model Context Protocol (MCP) provides a standardized way for servers to expose
 10 | resources to clients. Resources allow servers to share data that provides context to
 11 | language models, such as files, database schemas, or application-specific information.
 12 | Each resource is uniquely identified by a
 13 | [URI](https://datatracker.ietf.org/doc/html/rfc3986).
 14 | 
 15 | ## User Interaction Model
 16 | 
 17 | Resources in MCP are designed to be **application-driven**, with host applications
 18 | determining how to incorporate context based on their needs.
 19 | 
 20 | For example, applications could:
 21 | 
 22 | - Expose resources through UI elements for explicit selection, in a tree or list view
 23 | - Allow the user to search through and filter available resources
 24 | - Implement automatic context inclusion, based on heuristics or the AI model's selection
 25 | 
 26 | ![Example of resource context picker](resource-picker.png)
 27 | 
 28 | However, implementations are free to expose resources through any interface pattern that
 29 | suits their needs&mdash;the protocol itself does not mandate any specific user
 30 | interaction model.
 31 | 
 32 | ## Capabilities
 33 | 
 34 | Servers that support resources **MUST** declare the `resources` capability:
 35 | 
 36 | ```json
 37 | {
 38 |   "capabilities": {
 39 |     "resources": {
 40 |       "subscribe": true,
 41 |       "listChanged": true
 42 |     }
 43 |   }
 44 | }
 45 | ```
 46 | 
 47 | The capability supports two optional features:
 48 | 
 49 | - `subscribe`: whether the client can subscribe to be notified of changes to individual
 50 |   resources.
 51 | - `listChanged`: whether the server will emit notifications when the list of available
 52 |   resources changes.
 53 | 
 54 | Both `subscribe` and `listChanged` are optional&mdash;servers can support neither,
 55 | either, or both:
 56 | 
 57 | ```json
 58 | {
 59 |   "capabilities": {
 60 |     "resources": {} // Neither feature supported
 61 |   }
 62 | }
 63 | ```
 64 | 
 65 | ```json
 66 | {
 67 |   "capabilities": {
 68 |     "resources": {
 69 |       "subscribe": true // Only subscriptions supported
 70 |     }
 71 |   }
 72 | }
 73 | ```
 74 | 
 75 | ```json
 76 | {
 77 |   "capabilities": {
 78 |     "resources": {
 79 |       "listChanged": true // Only list change notifications supported
 80 |     }
 81 |   }
 82 | }
 83 | ```
 84 | 
 85 | ## Protocol Messages
 86 | 
 87 | ### Listing Resources
 88 | 
 89 | To discover available resources, clients send a `resources/list` request. This operation
 90 | supports
 91 | [pagination]({{< ref "/specification/2024-11-05/server/utilities/pagination" >}}).
 92 | 
 93 | **Request:**
 94 | 
 95 | ```json
 96 | {
 97 |   "jsonrpc": "2.0",
 98 |   "id": 1,
 99 |   "method": "resources/list",
100 |   "params": {
101 |     "cursor": "optional-cursor-value"
102 |   }
103 | }
104 | ```
105 | 
106 | **Response:**
107 | 
108 | ```json
109 | {
110 |   "jsonrpc": "2.0",
111 |   "id": 1,
112 |   "result": {
113 |     "resources": [
114 |       {
115 |         "uri": "file:///project/src/main.rs",
116 |         "name": "main.rs",
117 |         "description": "Primary application entry point",
118 |         "mimeType": "text/x-rust"
119 |       }
120 |     ],
121 |     "nextCursor": "next-page-cursor"
122 |   }
123 | }
124 | ```
125 | 
126 | ### Reading Resources
127 | 
128 | To retrieve resource contents, clients send a `resources/read` request:
129 | 
130 | **Request:**
131 | 
132 | ```json
133 | {
134 |   "jsonrpc": "2.0",
135 |   "id": 2,
136 |   "method": "resources/read",
137 |   "params": {
138 |     "uri": "file:///project/src/main.rs"
139 |   }
140 | }
141 | ```
142 | 
143 | **Response:**
144 | 
145 | ```json
146 | {
147 |   "jsonrpc": "2.0",
148 |   "id": 2,
149 |   "result": {
150 |     "contents": [
151 |       {
152 |         "uri": "file:///project/src/main.rs",
153 |         "mimeType": "text/x-rust",
154 |         "text": "fn main() {\n    println!(\"Hello world!\");\n}"
155 |       }
156 |     ]
157 |   }
158 | }
159 | ```
160 | 
161 | ### Resource Templates
162 | 
163 | Resource templates allow servers to expose parameterized resources using
164 | [URI templates](https://datatracker.ietf.org/doc/html/rfc6570). Arguments may be
165 | auto-completed through [the completion
166 | API]({{< ref "/specification/2024-11-05/server/utilities/completion" >}}).
167 | 
168 | **Request:**
169 | 
170 | ```json
171 | {
172 |   "jsonrpc": "2.0",
173 |   "id": 3,
174 |   "method": "resources/templates/list"
175 | }
176 | ```
177 | 
178 | **Response:**
179 | 
180 | ```json
181 | {
182 |   "jsonrpc": "2.0",
183 |   "id": 3,
184 |   "result": {
185 |     "resourceTemplates": [
186 |       {
187 |         "uriTemplate": "file:///{path}",
188 |         "name": "Project Files",
189 |         "description": "Access files in the project directory",
190 |         "mimeType": "application/octet-stream"
191 |       }
192 |     ]
193 |   }
194 | }
195 | ```
196 | 
197 | ### List Changed Notification
198 | 
199 | When the list of available resources changes, servers that declared the `listChanged`
200 | capability **SHOULD** send a notification:
201 | 
202 | ```json
203 | {
204 |   "jsonrpc": "2.0",
205 |   "method": "notifications/resources/list_changed"
206 | }
207 | ```
208 | 
209 | ### Subscriptions
210 | 
211 | The protocol supports optional subscriptions to resource changes. Clients can subscribe
212 | to specific resources and receive notifications when they change:
213 | 
214 | **Subscribe Request:**
215 | 
216 | ```json
217 | {
218 |   "jsonrpc": "2.0",
219 |   "id": 4,
220 |   "method": "resources/subscribe",
221 |   "params": {
222 |     "uri": "file:///project/src/main.rs"
223 |   }
224 | }
225 | ```
226 | 
227 | **Update Notification:**
228 | 
229 | ```json
230 | {
231 |   "jsonrpc": "2.0",
232 |   "method": "notifications/resources/updated",
233 |   "params": {
234 |     "uri": "file:///project/src/main.rs"
235 |   }
236 | }
237 | ```
238 | 
239 | ## Message Flow
240 | 
241 | ```mermaid
242 | sequenceDiagram
243 |     participant Client
244 |     participant Server
245 | 
246 |     Note over Client,Server: Resource Discovery
247 |     Client->>Server: resources/list
248 |     Server-->>Client: List of resources
249 | 
250 |     Note over Client,Server: Resource Access
251 |     Client->>Server: resources/read
252 |     Server-->>Client: Resource contents
253 | 
254 |     Note over Client,Server: Subscriptions
255 |     Client->>Server: resources/subscribe
256 |     Server-->>Client: Subscription confirmed
257 | 
258 |     Note over Client,Server: Updates
259 |     Server--)Client: notifications/resources/updated
260 |     Client->>Server: resources/read
261 |     Server-->>Client: Updated contents
262 | ```
263 | 
264 | ## Data Types
265 | 
266 | ### Resource
267 | 
268 | A resource definition includes:
269 | 
270 | - `uri`: Unique identifier for the resource
271 | - `name`: Human-readable name
272 | - `description`: Optional description
273 | - `mimeType`: Optional MIME type
274 | 
275 | ### Resource Contents
276 | 
277 | Resources can contain either text or binary data:
278 | 
279 | #### Text Content
280 | 
281 | ```json
282 | {
283 |   "uri": "file:///example.txt",
284 |   "mimeType": "text/plain",
285 |   "text": "Resource content"
286 | }
287 | ```
288 | 
289 | #### Binary Content
290 | 
291 | ```json
292 | {
293 |   "uri": "file:///example.png",
294 |   "mimeType": "image/png",
295 |   "blob": "base64-encoded-data"
296 | }
297 | ```
298 | 
299 | ## Common URI Schemes
300 | 
301 | The protocol defines several standard URI schemes. This list not
302 | exhaustive&mdash;implementations are always free to use additional, custom URI schemes.
303 | 
304 | ### https://
305 | 
306 | Used to represent a resource available on the web.
307 | 
308 | Servers **SHOULD** use this scheme only when the client is able to fetch and load the
309 | resource directly from the web on its own—that is, it doesn’t need to read the resource
310 | via the MCP server.
311 | 
312 | For other use cases, servers **SHOULD** prefer to use another URI scheme, or define a
313 | custom one, even if the server will itself be downloading resource contents over the
314 | internet.
315 | 
316 | ### file://
317 | 
318 | Used to identify resources that behave like a filesystem. However, the resources do not
319 | need to map to an actual physical filesystem.
320 | 
321 | MCP servers **MAY** identify file:// resources with an
322 | [XDG MIME type](https://specifications.freedesktop.org/shared-mime-info-spec/0.14/ar01s02.html#id-1.3.14),
323 | like `inode/directory`, to represent non-regular files (such as directories) that don’t
324 | otherwise have a standard MIME type.
325 | 
326 | ### git://
327 | 
328 | Git version control integration.
329 | 
330 | ## Error Handling
331 | 
332 | Servers **SHOULD** return standard JSON-RPC errors for common failure cases:
333 | 
334 | - Resource not found: `-32002`
335 | - Internal errors: `-32603`
336 | 
337 | Example error:
338 | 
339 | ```json
340 | {
341 |   "jsonrpc": "2.0",
342 |   "id": 5,
343 |   "error": {
344 |     "code": -32002,
345 |     "message": "Resource not found",
346 |     "data": {
347 |       "uri": "file:///nonexistent.txt"
348 |     }
349 |   }
350 | }
351 | ```
352 | 
353 | ## Security Considerations
354 | 
355 | 1. Servers **MUST** validate all resource URIs
356 | 2. Access controls **SHOULD** be implemented for sensitive resources
357 | 3. Binary data **MUST** be properly encoded
358 | 4. Resource permissions **SHOULD** be checked before operations
359 | 


--------------------------------------------------------------------------------
/docs/specification/2024-11-05/server/slash-command.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/modelcontextprotocol/specification/main/docs/specification/2024-11-05/server/slash-command.png


--------------------------------------------------------------------------------
/docs/specification/2024-11-05/server/tools.md:
--------------------------------------------------------------------------------
  1 | ---
  2 | title: Tools
  3 | type: docs
  4 | weight: 40
  5 | ---
  6 | 
  7 | {{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}
  8 | 
  9 | The Model Context Protocol (MCP) allows servers to expose tools that can be invoked by
 10 | language models. Tools enable models to interact with external systems, such as querying
 11 | databases, calling APIs, or performing computations. Each tool is uniquely identified by
 12 | a name and includes metadata describing its schema.
 13 | 
 14 | ## User Interaction Model
 15 | 
 16 | Tools in MCP are designed to be **model-controlled**, meaning that the language model can
 17 | discover and invoke tools automatically based on its contextual understanding and the
 18 | user's prompts.
 19 | 
 20 | However, implementations are free to expose tools through any interface pattern that
 21 | suits their needs&mdash;the protocol itself does not mandate any specific user
 22 | interaction model.
 23 | 
 24 | {{< callout type="warning" >}} For trust & safety and security, there **SHOULD** always
 25 | be a human in the loop with the ability to deny tool invocations.
 26 | 
 27 | Applications **SHOULD**:
 28 | 
 29 | - Provide UI that makes clear which tools are being exposed to the AI model
 30 | - Insert clear visual indicators when tools are invoked
 31 | - Present confirmation prompts to the user for operations, to ensure a human is in the
 32 |   loop {{< /callout >}}
 33 | 
 34 | ## Capabilities
 35 | 
 36 | Servers that support tools **MUST** declare the `tools` capability:
 37 | 
 38 | ```json
 39 | {
 40 |   "capabilities": {
 41 |     "tools": {
 42 |       "listChanged": true
 43 |     }
 44 |   }
 45 | }
 46 | ```
 47 | 
 48 | `listChanged` indicates whether the server will emit notifications when the list of
 49 | available tools changes.
 50 | 
 51 | ## Protocol Messages
 52 | 
 53 | ### Listing Tools
 54 | 
 55 | To discover available tools, clients send a `tools/list` request. This operation supports
 56 | [pagination]({{< ref "/specification/2024-11-05/server/utilities/pagination" >}}).
 57 | 
 58 | **Request:**
 59 | 
 60 | ```json
 61 | {
 62 |   "jsonrpc": "2.0",
 63 |   "id": 1,
 64 |   "method": "tools/list",
 65 |   "params": {
 66 |     "cursor": "optional-cursor-value"
 67 |   }
 68 | }
 69 | ```
 70 | 
 71 | **Response:**
 72 | 
 73 | ```json
 74 | {
 75 |   "jsonrpc": "2.0",
 76 |   "id": 1,
 77 |   "result": {
 78 |     "tools": [
 79 |       {
 80 |         "name": "get_weather",
 81 |         "description": "Get current weather information for a location",
 82 |         "inputSchema": {
 83 |           "type": "object",
 84 |           "properties": {
 85 |             "location": {
 86 |               "type": "string",
 87 |               "description": "City name or zip code"
 88 |             }
 89 |           },
 90 |           "required": ["location"]
 91 |         }
 92 |       }
 93 |     ],
 94 |     "nextCursor": "next-page-cursor"
 95 |   }
 96 | }
 97 | ```
 98 | 
 99 | ### Calling Tools
100 | 
101 | To invoke a tool, clients send a `tools/call` request:
102 | 
103 | **Request:**
104 | 
105 | ```json
106 | {
107 |   "jsonrpc": "2.0",
108 |   "id": 2,
109 |   "method": "tools/call",
110 |   "params": {
111 |     "name": "get_weather",
112 |     "arguments": {
113 |       "location": "New York"
114 |     }
115 |   }
116 | }
117 | ```
118 | 
119 | **Response:**
120 | 
121 | ```json
122 | {
123 |   "jsonrpc": "2.0",
124 |   "id": 2,
125 |   "result": {
126 |     "content": [
127 |       {
128 |         "type": "text",
129 |         "text": "Current weather in New York:\nTemperature: 72°F\nConditions: Partly cloudy"
130 |       }
131 |     ],
132 |     "isError": false
133 |   }
134 | }
135 | ```
136 | 
137 | ### List Changed Notification
138 | 
139 | When the list of available tools changes, servers that declared the `listChanged`
140 | capability **SHOULD** send a notification:
141 | 
142 | ```json
143 | {
144 |   "jsonrpc": "2.0",
145 |   "method": "notifications/tools/list_changed"
146 | }
147 | ```
148 | 
149 | ## Message Flow
150 | 
151 | ```mermaid
152 | sequenceDiagram
153 |     participant LLM
154 |     participant Client
155 |     participant Server
156 | 
157 |     Note over Client,Server: Discovery
158 |     Client->>Server: tools/list
159 |     Server-->>Client: List of tools
160 | 
161 |     Note over Client,LLM: Tool Selection
162 |     LLM->>Client: Select tool to use
163 | 
164 |     Note over Client,Server: Invocation
165 |     Client->>Server: tools/call
166 |     Server-->>Client: Tool result
167 |     Client->>LLM: Process result
168 | 
169 |     Note over Client,Server: Updates
170 |     Server--)Client: tools/list_changed
171 |     Client->>Server: tools/list
172 |     Server-->>Client: Updated tools
173 | ```
174 | 
175 | ## Data Types
176 | 
177 | ### Tool
178 | 
179 | A tool definition includes:
180 | 
181 | - `name`: Unique identifier for the tool
182 | - `description`: Human-readable description of functionality
183 | - `inputSchema`: JSON Schema defining expected parameters
184 | 
185 | ### Tool Result
186 | 
187 | Tool results can contain multiple content items of different types:
188 | 
189 | #### Text Content
190 | 
191 | ```json
192 | {
193 |   "type": "text",
194 |   "text": "Tool result text"
195 | }
196 | ```
197 | 
198 | #### Image Content
199 | 
200 | ```json
201 | {
202 |   "type": "image",
203 |   "data": "base64-encoded-data",
204 |   "mimeType": "image/png"
205 | }
206 | ```
207 | 
208 | #### Embedded Resources
209 | 
210 | [Resources]({{< ref "/specification/2024-11-05/server/resources" >}}) **MAY** be
211 | embedded, to provide additional context or data, behind a URI that can be subscribed to
212 | or fetched again by the client later:
213 | 
214 | ```json
215 | {
216 |   "type": "resource",
217 |   "resource": {
218 |     "uri": "resource://example",
219 |     "mimeType": "text/plain",
220 |     "text": "Resource content"
221 |   }
222 | }
223 | ```
224 | 
225 | ## Error Handling
226 | 
227 | Tools use two error reporting mechanisms:
228 | 
229 | 1. **Protocol Errors**: Standard JSON-RPC errors for issues like:
230 | 
231 |    - Unknown tools
232 |    - Invalid arguments
233 |    - Server errors
234 | 
235 | 2. **Tool Execution Errors**: Reported in tool results with `isError: true`:
236 |    - API failures
237 |    - Invalid input data
238 |    - Business logic errors
239 | 
240 | Example protocol error:
241 | 
242 | ```json
243 | {
244 |   "jsonrpc": "2.0",
245 |   "id": 3,
246 |   "error": {
247 |     "code": -32602,
248 |     "message": "Unknown tool: invalid_tool_name"
249 |   }
250 | }
251 | ```
252 | 
253 | Example tool execution error:
254 | 
255 | ```json
256 | {
257 |   "jsonrpc": "2.0",
258 |   "id": 4,
259 |   "result": {
260 |     "content": [
261 |       {
262 |         "type": "text",
263 |         "text": "Failed to fetch weather data: API rate limit exceeded"
264 |       }
265 |     ],
266 |     "isError": true
267 |   }
268 | }
269 | ```
270 | 
271 | ## Security Considerations
272 | 
273 | 1. Servers **MUST**:
274 | 
275 |    - Validate all tool inputs
276 |    - Implement proper access controls
277 |    - Rate limit tool invocations
278 |    - Sanitize tool outputs
279 | 
280 | 2. Clients **SHOULD**:
281 |    - Prompt for user confirmation on sensitive operations
282 |    - Show tool inputs to the user before calling the server, to avoid malicious or
283 |      accidental data exfiltration
284 |    - Validate tool results before passing to LLM
285 |    - Implement timeouts for tool calls
286 |    - Log tool usage for audit purposes
287 | 


--------------------------------------------------------------------------------
/docs/specification/2024-11-05/server/utilities/_index.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | title: Utilities
 3 | ---
 4 | 
 5 | {{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}
 6 | 
 7 | These optional features can be used to enhance server functionality.
 8 | 
 9 | {{< cards >}} {{< card link="completion" title="Completion" icon="at-symbol" >}}
10 | {{< card link="logging" title="Logging" icon="terminal" >}}
11 | {{< card link="pagination" title="Pagination" icon="collection" >}} {{< /cards >}}
12 | 


--------------------------------------------------------------------------------
/docs/specification/2024-11-05/server/utilities/completion.md:
--------------------------------------------------------------------------------
  1 | ---
  2 | title: Completion
  3 | ---
  4 | 
  5 | {{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}
  6 | 
  7 | The Model Context Protocol (MCP) provides a standardized way for servers to offer
  8 | argument autocompletion suggestions for prompts and resource URIs. This enables rich,
  9 | IDE-like experiences where users receive contextual suggestions while entering argument
 10 | values.
 11 | 
 12 | ## User Interaction Model
 13 | 
 14 | Completion in MCP is designed to support interactive user experiences similar to IDE code
 15 | completion.
 16 | 
 17 | For example, applications may show completion suggestions in a dropdown or popup menu as
 18 | users type, with the ability to filter and select from available options.
 19 | 
 20 | However, implementations are free to expose completion through any interface pattern that
 21 | suits their needs&mdash;the protocol itself does not mandate any specific user
 22 | interaction model.
 23 | 
 24 | ## Protocol Messages
 25 | 
 26 | ### Requesting Completions
 27 | 
 28 | To get completion suggestions, clients send a `completion/complete` request specifying
 29 | what is being completed through a reference type:
 30 | 
 31 | **Request:**
 32 | 
 33 | ```json
 34 | {
 35 |   "jsonrpc": "2.0",
 36 |   "id": 1,
 37 |   "method": "completion/complete",
 38 |   "params": {
 39 |     "ref": {
 40 |       "type": "ref/prompt",
 41 |       "name": "code_review"
 42 |     },
 43 |     "argument": {
 44 |       "name": "language",
 45 |       "value": "py"
 46 |     }
 47 |   }
 48 | }
 49 | ```
 50 | 
 51 | **Response:**
 52 | 
 53 | ```json
 54 | {
 55 |   "jsonrpc": "2.0",
 56 |   "id": 1,
 57 |   "result": {
 58 |     "completion": {
 59 |       "values": ["python", "pytorch", "pyside"],
 60 |       "total": 10,
 61 |       "hasMore": true
 62 |     }
 63 |   }
 64 | }
 65 | ```
 66 | 
 67 | ### Reference Types
 68 | 
 69 | The protocol supports two types of completion references:
 70 | 
 71 | | Type           | Description                 | Example                                             |
 72 | | -------------- | --------------------------- | --------------------------------------------------- |
 73 | | `ref/prompt`   | References a prompt by name | `{"type": "ref/prompt", "name": "code_review"}`     |
 74 | | `ref/resource` | References a resource URI   | `{"type": "ref/resource", "uri": "file:///{path}"}` |
 75 | 
 76 | ### Completion Results
 77 | 
 78 | Servers return an array of completion values ranked by relevance, with:
 79 | 
 80 | - Maximum 100 items per response
 81 | - Optional total number of available matches
 82 | - Boolean indicating if additional results exist
 83 | 
 84 | ## Message Flow
 85 | 
 86 | ```mermaid
 87 | sequenceDiagram
 88 |     participant Client
 89 |     participant Server
 90 | 
 91 |     Note over Client: User types argument
 92 |     Client->>Server: completion/complete
 93 |     Server-->>Client: Completion suggestions
 94 | 
 95 |     Note over Client: User continues typing
 96 |     Client->>Server: completion/complete
 97 |     Server-->>Client: Refined suggestions
 98 | ```
 99 | 
100 | ## Data Types
101 | 
102 | ### CompleteRequest
103 | 
104 | - `ref`: A `PromptReference` or `ResourceReference`
105 | - `argument`: Object containing:
106 |   - `name`: Argument name
107 |   - `value`: Current value
108 | 
109 | ### CompleteResult
110 | 
111 | - `completion`: Object containing:
112 |   - `values`: Array of suggestions (max 100)
113 |   - `total`: Optional total matches
114 |   - `hasMore`: Additional results flag
115 | 
116 | ## Implementation Considerations
117 | 
118 | 1. Servers **SHOULD**:
119 | 
120 |    - Return suggestions sorted by relevance
121 |    - Implement fuzzy matching where appropriate
122 |    - Rate limit completion requests
123 |    - Validate all inputs
124 | 
125 | 2. Clients **SHOULD**:
126 |    - Debounce rapid completion requests
127 |    - Cache completion results where appropriate
128 |    - Handle missing or partial results gracefully
129 | 
130 | ## Security
131 | 
132 | Implementations **MUST**:
133 | 
134 | - Validate all completion inputs
135 | - Implement appropriate rate limiting
136 | - Control access to sensitive suggestions
137 | - Prevent completion-based information disclosure
138 | 


--------------------------------------------------------------------------------
/docs/specification/2024-11-05/server/utilities/logging.md:
--------------------------------------------------------------------------------
  1 | ---
  2 | title: Logging
  3 | ---
  4 | 
  5 | {{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}
  6 | 
  7 | The Model Context Protocol (MCP) provides a standardized way for servers to send
  8 | structured log messages to clients. Clients can control logging verbosity by setting
  9 | minimum log levels, with servers sending notifications containing severity levels,
 10 | optional logger names, and arbitrary JSON-serializable data.
 11 | 
 12 | ## User Interaction Model
 13 | 
 14 | Implementations are free to expose logging through any interface pattern that suits their
 15 | needs&mdash;the protocol itself does not mandate any specific user interaction model.
 16 | 
 17 | ## Capabilities
 18 | 
 19 | Servers that emit log message notifications **MUST** declare the `logging` capability:
 20 | 
 21 | ```json
 22 | {
 23 |   "capabilities": {
 24 |     "logging": {}
 25 |   }
 26 | }
 27 | ```
 28 | 
 29 | ## Log Levels
 30 | 
 31 | The protocol follows the standard syslog severity levels specified in
 32 | [RFC 5424](https://datatracker.ietf.org/doc/html/rfc5424#section-6.2.1):
 33 | 
 34 | | Level     | Description                      | Example Use Case           |
 35 | | --------- | -------------------------------- | -------------------------- |
 36 | | debug     | Detailed debugging information   | Function entry/exit points |
 37 | | info      | General informational messages   | Operation progress updates |
 38 | | notice    | Normal but significant events    | Configuration changes      |
 39 | | warning   | Warning conditions               | Deprecated feature usage   |
 40 | | error     | Error conditions                 | Operation failures         |
 41 | | critical  | Critical conditions              | System component failures  |
 42 | | alert     | Action must be taken immediately | Data corruption detected   |
 43 | | emergency | System is unusable               | Complete system failure    |
 44 | 
 45 | ## Protocol Messages
 46 | 
 47 | ### Setting Log Level
 48 | 
 49 | To configure the minimum log level, clients **MAY** send a `logging/setLevel` request:
 50 | 
 51 | **Request:**
 52 | 
 53 | ```json
 54 | {
 55 |   "jsonrpc": "2.0",
 56 |   "id": 1,
 57 |   "method": "logging/setLevel",
 58 |   "params": {
 59 |     "level": "info"
 60 |   }
 61 | }
 62 | ```
 63 | 
 64 | ### Log Message Notifications
 65 | 
 66 | Servers send log messages using `notifications/message` notifications:
 67 | 
 68 | ```json
 69 | {
 70 |   "jsonrpc": "2.0",
 71 |   "method": "notifications/message",
 72 |   "params": {
 73 |     "level": "error",
 74 |     "logger": "database",
 75 |     "data": {
 76 |       "error": "Connection failed",
 77 |       "details": {
 78 |         "host": "localhost",
 79 |         "port": 5432
 80 |       }
 81 |     }
 82 |   }
 83 | }
 84 | ```
 85 | 
 86 | ## Message Flow
 87 | 
 88 | ```mermaid
 89 | sequenceDiagram
 90 |     participant Client
 91 |     participant Server
 92 | 
 93 |     Note over Client,Server: Configure Logging
 94 |     Client->>Server: logging/setLevel (info)
 95 |     Server-->>Client: Empty Result
 96 | 
 97 |     Note over Client,Server: Server Activity
 98 |     Server--)Client: notifications/message (info)
 99 |     Server--)Client: notifications/message (warning)
100 |     Server--)Client: notifications/message (error)
101 | 
102 |     Note over Client,Server: Level Change
103 |     Client->>Server: logging/setLevel (error)
104 |     Server-->>Client: Empty Result
105 |     Note over Server: Only sends error level<br/>and above
106 | ```
107 | 
108 | ## Error Handling
109 | 
110 | Servers **SHOULD** return standard JSON-RPC errors for common failure cases:
111 | 
112 | - Invalid log level: `-32602` (Invalid params)
113 | - Configuration errors: `-32603` (Internal error)
114 | 
115 | ## Implementation Considerations
116 | 
117 | 1. Servers **SHOULD**:
118 | 
119 |    - Rate limit log messages
120 |    - Include relevant context in data field
121 |    - Use consistent logger names
122 |    - Remove sensitive information
123 | 
124 | 2. Clients **MAY**:
125 |    - Present log messages in the UI
126 |    - Implement log filtering/search
127 |    - Display severity visually
128 |    - Persist log messages
129 | 
130 | ## Security
131 | 
132 | 1. Log messages **MUST NOT** contain:
133 | 
134 |    - Credentials or secrets
135 |    - Personal identifying information
136 |    - Internal system details that could aid attacks
137 | 
138 | 2. Implementations **SHOULD**:
139 |    - Rate limit messages
140 |    - Validate all data fields
141 |    - Control log access
142 |    - Monitor for sensitive content
143 | 


--------------------------------------------------------------------------------
/docs/specification/2024-11-05/server/utilities/pagination.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | title: Pagination
 3 | ---
 4 | 
 5 | {{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}
 6 | 
 7 | The Model Context Protocol (MCP) supports paginating list operations that may return
 8 | large result sets. Pagination allows servers to yield results in smaller chunks rather
 9 | than all at once.
10 | 
11 | Pagination is especially important when connecting to external services over the
12 | internet, but also useful for local integrations to avoid performance issues with large
13 | data sets.
14 | 
15 | ## Pagination Model
16 | 
17 | Pagination in MCP uses an opaque cursor-based approach, instead of numbered pages.
18 | 
19 | - The **cursor** is an opaque string token, representing a position in the result set
20 | - **Page size** is determined by the server, and **MAY NOT** be fixed
21 | 
22 | ## Response Format
23 | 
24 | Pagination starts when the server sends a **response** that includes:
25 | 
26 | - The current page of results
27 | - An optional `nextCursor` field if more results exist
28 | 
29 | ```json
30 | {
31 |   "jsonrpc": "2.0",
32 |   "id": "123",
33 |   "result": {
34 |     "resources": [...],
35 |     "nextCursor": "eyJwYWdlIjogM30="
36 |   }
37 | }
38 | ```
39 | 
40 | ## Request Format
41 | 
42 | After receiving a cursor, the client can _continue_ paginating by issuing a request
43 | including that cursor:
44 | 
45 | ```json
46 | {
47 |   "jsonrpc": "2.0",
48 |   "method": "resources/list",
49 |   "params": {
50 |     "cursor": "eyJwYWdlIjogMn0="
51 |   }
52 | }
53 | ```
54 | 
55 | ## Pagination Flow
56 | 
57 | ```mermaid
58 | sequenceDiagram
59 |     participant Client
60 |     participant Server
61 | 
62 |     Client->>Server: List Request (no cursor)
63 |     loop Pagination Loop
64 |       Server-->>Client: Page of results + nextCursor
65 |       Client->>Server: List Request (with cursor)
66 |     end
67 | ```
68 | 
69 | ## Operations Supporting Pagination
70 | 
71 | The following MCP operations support pagination:
72 | 
73 | - `resources/list` - List available resources
74 | - `resources/templates/list` - List resource templates
75 | - `prompts/list` - List available prompts
76 | - `tools/list` - List available tools
77 | 
78 | ## Implementation Guidelines
79 | 
80 | 1. Servers **SHOULD**:
81 | 
82 |    - Provide stable cursors
83 |    - Handle invalid cursors gracefully
84 | 
85 | 2. Clients **SHOULD**:
86 | 
87 |    - Treat a missing `nextCursor` as the end of results
88 |    - Support both paginated and non-paginated flows
89 | 
90 | 3. Clients **MUST** treat cursors as opaque tokens:
91 |    - Don't make assumptions about cursor format
92 |    - Don't attempt to parse or modify cursors
93 |    - Don't persist cursors across sessions
94 | 
95 | ## Error Handling
96 | 
97 | Invalid cursors **SHOULD** result in an error with code -32602 (Invalid params).
98 | 


--------------------------------------------------------------------------------

```
Page 1/2FirstPrevNextLast