Showing preview only (2,684K chars total). Download the full file or copy to clipboard to get everything.
Repository: modelcontextprotocol/python-sdk
Branch: main
Commit: 883d89309755
Files: 432
Total size: 2.5 MB
Directory structure:
gitextract_oto7xmdg/
├── .claude/
│ └── commands/
│ └── review-pr.md
├── .git-blame-ignore-revs
├── .gitattribute
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug.yaml
│ │ ├── config.yaml
│ │ ├── feature-request.yaml
│ │ └── question.yaml
│ ├── actions/
│ │ └── conformance/
│ │ ├── client.py
│ │ └── run-server.sh
│ ├── dependabot.yml
│ └── workflows/
│ ├── claude-code-review.yml
│ ├── claude.yml
│ ├── comment-on-release.yml
│ ├── conformance.yml
│ ├── main.yml
│ ├── publish-docs-manually.yml
│ ├── publish-pypi.yml
│ ├── shared.yml
│ └── weekly-lockfile-update.yml
├── .gitignore
├── .pre-commit-config.yaml
├── CLAUDE.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── README.v2.md
├── RELEASE.md
├── SECURITY.md
├── docs/
│ ├── authorization.md
│ ├── concepts.md
│ ├── experimental/
│ │ ├── index.md
│ │ ├── tasks-client.md
│ │ ├── tasks-server.md
│ │ └── tasks.md
│ ├── hooks/
│ │ └── gen_ref_pages.py
│ ├── index.md
│ ├── installation.md
│ ├── low-level-server.md
│ ├── migration.md
│ └── testing.md
├── examples/
│ ├── README.md
│ ├── clients/
│ │ ├── simple-auth-client/
│ │ │ ├── README.md
│ │ │ ├── mcp_simple_auth_client/
│ │ │ │ ├── __init__.py
│ │ │ │ └── main.py
│ │ │ └── pyproject.toml
│ │ ├── simple-chatbot/
│ │ │ ├── README.MD
│ │ │ ├── mcp_simple_chatbot/
│ │ │ │ ├── main.py
│ │ │ │ ├── requirements.txt
│ │ │ │ └── servers_config.json
│ │ │ └── pyproject.toml
│ │ ├── simple-task-client/
│ │ │ ├── README.md
│ │ │ ├── mcp_simple_task_client/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ └── main.py
│ │ │ └── pyproject.toml
│ │ ├── simple-task-interactive-client/
│ │ │ ├── README.md
│ │ │ ├── mcp_simple_task_interactive_client/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ └── main.py
│ │ │ └── pyproject.toml
│ │ └── sse-polling-client/
│ │ ├── README.md
│ │ ├── mcp_sse_polling_client/
│ │ │ ├── __init__.py
│ │ │ └── main.py
│ │ └── pyproject.toml
│ ├── mcpserver/
│ │ ├── complex_inputs.py
│ │ ├── desktop.py
│ │ ├── direct_call_tool_result_return.py
│ │ ├── echo.py
│ │ ├── icons_demo.py
│ │ ├── logging_and_progress.py
│ │ ├── memory.py
│ │ ├── parameter_descriptions.py
│ │ ├── readme-quickstart.py
│ │ ├── screenshot.py
│ │ ├── simple_echo.py
│ │ ├── text_me.py
│ │ ├── unicode_example.py
│ │ └── weather_structured.py
│ ├── servers/
│ │ ├── everything-server/
│ │ │ ├── README.md
│ │ │ ├── mcp_everything_server/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ └── server.py
│ │ │ └── pyproject.toml
│ │ ├── simple-auth/
│ │ │ ├── README.md
│ │ │ ├── mcp_simple_auth/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ ├── auth_server.py
│ │ │ │ ├── legacy_as_server.py
│ │ │ │ ├── py.typed
│ │ │ │ ├── server.py
│ │ │ │ ├── simple_auth_provider.py
│ │ │ │ └── token_verifier.py
│ │ │ └── pyproject.toml
│ │ ├── simple-pagination/
│ │ │ ├── README.md
│ │ │ ├── mcp_simple_pagination/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ └── server.py
│ │ │ └── pyproject.toml
│ │ ├── simple-prompt/
│ │ │ ├── README.md
│ │ │ ├── mcp_simple_prompt/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ └── server.py
│ │ │ └── pyproject.toml
│ │ ├── simple-resource/
│ │ │ ├── README.md
│ │ │ ├── mcp_simple_resource/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ └── server.py
│ │ │ └── pyproject.toml
│ │ ├── simple-streamablehttp/
│ │ │ ├── README.md
│ │ │ ├── mcp_simple_streamablehttp/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ ├── event_store.py
│ │ │ │ └── server.py
│ │ │ └── pyproject.toml
│ │ ├── simple-streamablehttp-stateless/
│ │ │ ├── README.md
│ │ │ ├── mcp_simple_streamablehttp_stateless/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ └── server.py
│ │ │ └── pyproject.toml
│ │ ├── simple-task/
│ │ │ ├── README.md
│ │ │ ├── mcp_simple_task/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ └── server.py
│ │ │ └── pyproject.toml
│ │ ├── simple-task-interactive/
│ │ │ ├── README.md
│ │ │ ├── mcp_simple_task_interactive/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ └── server.py
│ │ │ └── pyproject.toml
│ │ ├── simple-tool/
│ │ │ ├── README.md
│ │ │ ├── mcp_simple_tool/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ └── server.py
│ │ │ └── pyproject.toml
│ │ ├── sse-polling-demo/
│ │ │ ├── README.md
│ │ │ ├── mcp_sse_polling_demo/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ ├── event_store.py
│ │ │ │ └── server.py
│ │ │ └── pyproject.toml
│ │ └── structured-output-lowlevel/
│ │ ├── mcp_structured_output_lowlevel/
│ │ │ ├── __init__.py
│ │ │ └── __main__.py
│ │ └── pyproject.toml
│ └── snippets/
│ ├── clients/
│ │ ├── __init__.py
│ │ ├── completion_client.py
│ │ ├── display_utilities.py
│ │ ├── oauth_client.py
│ │ ├── pagination_client.py
│ │ ├── parsing_tool_results.py
│ │ ├── stdio_client.py
│ │ ├── streamable_basic.py
│ │ └── url_elicitation_client.py
│ ├── pyproject.toml
│ └── servers/
│ ├── __init__.py
│ ├── basic_prompt.py
│ ├── basic_resource.py
│ ├── basic_tool.py
│ ├── completion.py
│ ├── direct_call_tool_result.py
│ ├── direct_execution.py
│ ├── elicitation.py
│ ├── images.py
│ ├── lifespan_example.py
│ ├── lowlevel/
│ │ ├── __init__.py
│ │ ├── basic.py
│ │ ├── direct_call_tool_result.py
│ │ ├── lifespan.py
│ │ └── structured_output.py
│ ├── mcpserver_quickstart.py
│ ├── notifications.py
│ ├── oauth_server.py
│ ├── pagination_example.py
│ ├── sampling.py
│ ├── streamable_config.py
│ ├── streamable_http_basic_mounting.py
│ ├── streamable_http_host_mounting.py
│ ├── streamable_http_multiple_servers.py
│ ├── streamable_http_path_config.py
│ ├── streamable_starlette_mount.py
│ ├── structured_output.py
│ └── tool_progress.py
├── mkdocs.yml
├── pyproject.toml
├── scripts/
│ ├── test
│ └── update_readme_snippets.py
├── src/
│ └── mcp/
│ ├── __init__.py
│ ├── cli/
│ │ ├── __init__.py
│ │ ├── claude.py
│ │ └── cli.py
│ ├── client/
│ │ ├── __init__.py
│ │ ├── __main__.py
│ │ ├── _memory.py
│ │ ├── _transport.py
│ │ ├── auth/
│ │ │ ├── __init__.py
│ │ │ ├── exceptions.py
│ │ │ ├── extensions/
│ │ │ │ ├── __init__.py
│ │ │ │ └── client_credentials.py
│ │ │ ├── oauth2.py
│ │ │ └── utils.py
│ │ ├── client.py
│ │ ├── context.py
│ │ ├── experimental/
│ │ │ ├── __init__.py
│ │ │ ├── task_handlers.py
│ │ │ └── tasks.py
│ │ ├── session.py
│ │ ├── session_group.py
│ │ ├── sse.py
│ │ ├── stdio.py
│ │ ├── streamable_http.py
│ │ └── websocket.py
│ ├── os/
│ │ ├── __init__.py
│ │ ├── posix/
│ │ │ ├── __init__.py
│ │ │ └── utilities.py
│ │ └── win32/
│ │ ├── __init__.py
│ │ └── utilities.py
│ ├── py.typed
│ ├── server/
│ │ ├── __init__.py
│ │ ├── __main__.py
│ │ ├── auth/
│ │ │ ├── __init__.py
│ │ │ ├── errors.py
│ │ │ ├── handlers/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── authorize.py
│ │ │ │ ├── metadata.py
│ │ │ │ ├── register.py
│ │ │ │ ├── revoke.py
│ │ │ │ └── token.py
│ │ │ ├── json_response.py
│ │ │ ├── middleware/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── auth_context.py
│ │ │ │ ├── bearer_auth.py
│ │ │ │ └── client_auth.py
│ │ │ ├── provider.py
│ │ │ ├── routes.py
│ │ │ └── settings.py
│ │ ├── context.py
│ │ ├── elicitation.py
│ │ ├── experimental/
│ │ │ ├── __init__.py
│ │ │ ├── request_context.py
│ │ │ ├── session_features.py
│ │ │ ├── task_context.py
│ │ │ ├── task_result_handler.py
│ │ │ └── task_support.py
│ │ ├── lowlevel/
│ │ │ ├── __init__.py
│ │ │ ├── experimental.py
│ │ │ ├── helper_types.py
│ │ │ └── server.py
│ │ ├── mcpserver/
│ │ │ ├── __init__.py
│ │ │ ├── context.py
│ │ │ ├── exceptions.py
│ │ │ ├── prompts/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── base.py
│ │ │ │ └── manager.py
│ │ │ ├── resources/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── base.py
│ │ │ │ ├── resource_manager.py
│ │ │ │ ├── templates.py
│ │ │ │ └── types.py
│ │ │ ├── server.py
│ │ │ ├── tools/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── base.py
│ │ │ │ └── tool_manager.py
│ │ │ └── utilities/
│ │ │ ├── __init__.py
│ │ │ ├── context_injection.py
│ │ │ ├── func_metadata.py
│ │ │ ├── logging.py
│ │ │ └── types.py
│ │ ├── models.py
│ │ ├── session.py
│ │ ├── sse.py
│ │ ├── stdio.py
│ │ ├── streamable_http.py
│ │ ├── streamable_http_manager.py
│ │ ├── transport_security.py
│ │ ├── validation.py
│ │ └── websocket.py
│ ├── shared/
│ │ ├── __init__.py
│ │ ├── _context.py
│ │ ├── _httpx_utils.py
│ │ ├── auth.py
│ │ ├── auth_utils.py
│ │ ├── exceptions.py
│ │ ├── experimental/
│ │ │ ├── __init__.py
│ │ │ └── tasks/
│ │ │ ├── __init__.py
│ │ │ ├── capabilities.py
│ │ │ ├── context.py
│ │ │ ├── helpers.py
│ │ │ ├── in_memory_task_store.py
│ │ │ ├── message_queue.py
│ │ │ ├── polling.py
│ │ │ ├── resolver.py
│ │ │ └── store.py
│ │ ├── memory.py
│ │ ├── message.py
│ │ ├── metadata_utils.py
│ │ ├── response_router.py
│ │ ├── session.py
│ │ ├── tool_name_validation.py
│ │ └── version.py
│ └── types/
│ ├── __init__.py
│ ├── _types.py
│ └── jsonrpc.py
└── tests/
├── __init__.py
├── cli/
│ ├── __init__.py
│ ├── test_claude.py
│ └── test_utils.py
├── client/
│ ├── __init__.py
│ ├── auth/
│ │ └── extensions/
│ │ └── test_client_credentials.py
│ ├── conftest.py
│ ├── test_auth.py
│ ├── test_client.py
│ ├── test_http_unicode.py
│ ├── test_list_methods_cursor.py
│ ├── test_list_roots_callback.py
│ ├── test_logging_callback.py
│ ├── test_notification_response.py
│ ├── test_output_schema_validation.py
│ ├── test_resource_cleanup.py
│ ├── test_sampling_callback.py
│ ├── test_scope_bug_1630.py
│ ├── test_session.py
│ ├── test_session_group.py
│ ├── test_stdio.py
│ ├── test_transport_stream_cleanup.py
│ └── transports/
│ ├── __init__.py
│ └── test_memory.py
├── conftest.py
├── experimental/
│ ├── __init__.py
│ └── tasks/
│ ├── __init__.py
│ ├── client/
│ │ ├── __init__.py
│ │ ├── test_capabilities.py
│ │ ├── test_handlers.py
│ │ ├── test_poll_task.py
│ │ └── test_tasks.py
│ ├── server/
│ │ ├── __init__.py
│ │ ├── test_context.py
│ │ ├── test_integration.py
│ │ ├── test_run_task_flow.py
│ │ ├── test_server.py
│ │ ├── test_server_task_context.py
│ │ ├── test_store.py
│ │ └── test_task_result_handler.py
│ ├── test_capabilities.py
│ ├── test_elicitation_scenarios.py
│ ├── test_message_queue.py
│ ├── test_request_context.py
│ └── test_spec_compliance.py
├── issues/
│ ├── test_100_tool_listing.py
│ ├── test_1027_win_unreachable_cleanup.py
│ ├── test_129_resource_templates.py
│ ├── test_1338_icons_and_metadata.py
│ ├── test_1363_race_condition_streamable_http.py
│ ├── test_141_resource_templates.py
│ ├── test_152_resource_mime_type.py
│ ├── test_1574_resource_uri_validation.py
│ ├── test_1754_mime_type_parameters.py
│ ├── test_176_progress_token.py
│ ├── test_188_concurrency.py
│ ├── test_192_request_id.py
│ ├── test_342_base64_encoding.py
│ ├── test_355_type_error.py
│ ├── test_552_windows_hang.py
│ ├── test_88_random_error.py
│ ├── test_973_url_decoding.py
│ └── test_malformed_input.py
├── server/
│ ├── __init__.py
│ ├── auth/
│ │ ├── __init__.py
│ │ ├── middleware/
│ │ │ ├── __init__.py
│ │ │ ├── test_auth_context.py
│ │ │ └── test_bearer_auth.py
│ │ ├── test_error_handling.py
│ │ ├── test_protected_resource.py
│ │ ├── test_provider.py
│ │ └── test_routes.py
│ ├── lowlevel/
│ │ ├── __init__.py
│ │ ├── test_helper_types.py
│ │ ├── test_server_listing.py
│ │ └── test_server_pagination.py
│ ├── mcpserver/
│ │ ├── __init__.py
│ │ ├── auth/
│ │ │ ├── __init__.py
│ │ │ └── test_auth_integration.py
│ │ ├── prompts/
│ │ │ ├── __init__.py
│ │ │ ├── test_base.py
│ │ │ └── test_manager.py
│ │ ├── resources/
│ │ │ ├── __init__.py
│ │ │ ├── test_file_resources.py
│ │ │ ├── test_function_resources.py
│ │ │ ├── test_resource_manager.py
│ │ │ ├── test_resource_template.py
│ │ │ └── test_resources.py
│ │ ├── servers/
│ │ │ ├── __init__.py
│ │ │ └── test_file_server.py
│ │ ├── test_elicitation.py
│ │ ├── test_func_metadata.py
│ │ ├── test_integration.py
│ │ ├── test_parameter_descriptions.py
│ │ ├── test_server.py
│ │ ├── test_title.py
│ │ ├── test_tool_manager.py
│ │ ├── test_url_elicitation.py
│ │ ├── test_url_elicitation_error_throw.py
│ │ └── tools/
│ │ ├── __init__.py
│ │ └── test_base.py
│ ├── test_cancel_handling.py
│ ├── test_completion_with_context.py
│ ├── test_lifespan.py
│ ├── test_lowlevel_exception_handling.py
│ ├── test_lowlevel_tool_annotations.py
│ ├── test_read_resource.py
│ ├── test_session.py
│ ├── test_session_race_condition.py
│ ├── test_sse_security.py
│ ├── test_stateless_mode.py
│ ├── test_stdio.py
│ ├── test_streamable_http_manager.py
│ ├── test_streamable_http_security.py
│ └── test_validation.py
├── shared/
│ ├── __init__.py
│ ├── test_auth.py
│ ├── test_auth_utils.py
│ ├── test_exceptions.py
│ ├── test_httpx_utils.py
│ ├── test_progress_notifications.py
│ ├── test_session.py
│ ├── test_sse.py
│ ├── test_streamable_http.py
│ ├── test_tool_name_validation.py
│ ├── test_win32_utils.py
│ └── test_ws.py
├── test_examples.py
├── test_helpers.py
└── test_types.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .claude/commands/review-pr.md
================================================
Review the pull request: $ARGUMENTS
Follow these steps carefully. Use the `gh` CLI for all GitHub interactions.
## Step 1: Resolve the PR
Parse `$ARGUMENTS` to determine the PR. It can be:
- A full URL like `https://github.com/owner/repo/pull/123`
- A `owner/repo#123` reference
- A bare number like `123` (use the current repo)
- A description — search for it with `gh pr list --search "<description>" --limit 5` and pick the best match
Once resolved, fetch the PR metadata:
```bash
gh pr view <PR> --json number,title,body,author,state,baseRefName,headRefName,url,labels,milestone,additions,deletions,changedFiles,createdAt,updatedAt,mergedAt,reviewDecision,reviews,assignees
```
## Step 2: Gather the diff
Get the full diff of the PR:
```bash
gh pr diff <PR>
```
If the diff is very large (>3000 lines), focus on the most important files first and summarize the rest.
## Step 3: Collect PR discussion context
Fetch all comments and review threads:
```bash
gh api repos/{owner}/{repo}/pulls/{number}/comments --paginate
gh api repos/{owner}/{repo}/issues/{number}/comments --paginate
gh api repos/{owner}/{repo}/pulls/{number}/reviews --paginate
```
Pay attention to:
- Reviewer feedback and requested changes
- Author responses and explanations
- Any unresolved conversations
- Approval or rejection status
## Step 4: Find and read linked issues
Look for issue references in:
- The PR body (patterns like `#123`, `fixes #123`, `closes #123`, `resolves #123`)
- The PR branch name (patterns like `issue-123`, `fix/123`)
- Commit messages
For each linked issue, fetch its content:
```bash
gh issue view <number> --json title,body,comments,labels,state
```
Read through issue comments to understand the original problem, user reports, and any discussed solutions.
## Step 5: Analyze and validate
With all context gathered, analyze the PR critically:
1. **Intent alignment**: Does the code change actually solve the problem described in the PR and/or linked issues?
2. **Completeness**: Are there aspects of the issue or requested feature that the PR doesn't address?
3. **Scope**: Does the PR include changes unrelated to the stated goal? Are there unnecessary modifications?
4. **Correctness**: Based on the diff, are there obvious bugs, edge cases, or logic errors?
5. **Testing**: Does the PR include tests? Are they meaningful and do they cover the important cases?
6. **Breaking changes**: Could this PR break existing functionality or APIs?
7. **Unresolved feedback**: Are there reviewer comments that haven't been addressed?
## Step 6: Produce the review summary
Present the summary in this format:
---
### PR Review: `<title>` (<url>)
**Author:** <author> | **Status:** <state> | **Review decision:** <decision>
**Base:** `<base>` ← `<head>` | **Changed files:** <n> | **+<additions> / -<deletions>**
#### Problem
<1-3 sentences describing what problem this PR is trying to solve, based on the PR description and linked issues>
#### Solution
<1-3 sentences describing the approach taken in the code>
#### Key changes
<Bulleted list of the most important changes, grouped by theme. Include file paths.>
#### Linked issues
<List of linked issues with their title, state, and a one-line summary of the discussion>
#### Discussion highlights
<Summary of important comments from reviewers and the author. Flag any unresolved threads.>
#### Concerns
<List any issues found during validation: bugs, missing tests, scope creep, unaddressed feedback, etc. If none, say "No concerns found.">
#### Verdict
<One of: APPROVE / REQUEST CHANGES / NEEDS DISCUSSION, with a brief justification>
#### Suggested action
<Clear recommendation for the reviewer: what to approve, what to push back on, what to ask about>
---
================================================
FILE: .git-blame-ignore-revs
================================================
# Applied 120 line-length rule to all files: https://github.com/modelcontextprotocol/python-sdk/pull/856
543961968c0634e93d919d509cce23a1d6a56c21
# Added 100% code coverage baseline with pragma comments: https://github.com/modelcontextprotocol/python-sdk/pull/1553
89e9c43acf7e23cf766357d776ec1ce63ac2c58e
================================================
FILE: .gitattribute
================================================
# Generated
uv.lock linguist-generated=true
================================================
FILE: .github/ISSUE_TEMPLATE/bug.yaml
================================================
name: 🐛 MCP Python SDK Bug
description: Report a bug or unexpected behavior in the MCP Python SDK
labels: ["need confirmation"]
body:
- type: markdown
attributes:
value: Thank you for contributing to the MCP Python SDK! ✊
- type: checkboxes
id: checks
attributes:
label: Initial Checks
description: Just making sure you're using the latest version of MCP Python SDK.
options:
- label: I confirm that I'm using the latest version of MCP Python SDK
required: true
- label: I confirm that I searched for my issue in https://github.com/modelcontextprotocol/python-sdk/issues before opening this issue
required: true
- type: textarea
id: description
attributes:
label: Description
description: |
Please explain what you're seeing and what you would expect to see.
Please provide as much detail as possible to make understanding and solving your problem as quick as possible. 🙏
validations:
required: true
- type: textarea
id: example
attributes:
label: Example Code
description: >
If applicable, please add a self-contained,
[minimal, reproducible, example](https://stackoverflow.com/help/minimal-reproducible-example)
demonstrating the bug.
placeholder: |
from mcp.server.mcpserver import MCPServer
...
render: Python
- type: textarea
id: version
attributes:
label: Python & MCP Python SDK
description: |
Which version of Python and MCP Python SDK are you using?
render: Text
validations:
required: true
================================================
FILE: .github/ISSUE_TEMPLATE/config.yaml
================================================
blank_issues_enabled: false
================================================
FILE: .github/ISSUE_TEMPLATE/feature-request.yaml
================================================
name: 🚀 MCP Python SDK Feature Request
description: "Suggest a new feature for the MCP Python SDK"
labels: ["feature request"]
body:
- type: markdown
attributes:
value: Thank you for contributing to the MCP Python SDK! ✊
- type: textarea
id: description
attributes:
label: Description
description: |
Please give as much detail as possible about the feature you would like to suggest. 🙏
You might like to add:
* A demo of how code might look when using the feature
* Your use case(s) for the feature
* Reference to other projects that have a similar feature
validations:
required: true
- type: textarea
id: references
attributes:
label: References
description: |
Please add any links or references that might help us understand your feature request better. 📚
================================================
FILE: .github/ISSUE_TEMPLATE/question.yaml
================================================
name: ❓ MCP Python SDK Question
description: "Ask a question about the MCP Python SDK"
labels: ["question"]
body:
- type: markdown
attributes:
value: Thank you for reaching out to the MCP Python SDK community! We're here to help! 🤝
- type: textarea
id: question
attributes:
label: Question
description: |
Please provide as much detail as possible about your question. 🙏
You might like to include:
* Code snippets showing what you've tried
* Error messages you're encountering (if any)
* Expected vs actual behavior
* Your use case and what you're trying to achieve
validations:
required: true
- type: textarea
id: context
attributes:
label: Additional Context
description: |
Please provide any additional context that might help us better understand your question, such as:
* Your MCP Python SDK version
* Your Python version
* Relevant configuration or environment details 📝
================================================
FILE: .github/actions/conformance/client.py
================================================
"""MCP unified conformance test client.
This client is designed to work with the @modelcontextprotocol/conformance npm package.
It handles all conformance test scenarios via environment variables and CLI arguments.
Contract:
- MCP_CONFORMANCE_SCENARIO env var -> scenario name
- MCP_CONFORMANCE_CONTEXT env var -> optional JSON (for client-credentials scenarios)
- Server URL as last CLI argument (sys.argv[1])
- Must exit 0 within 30 seconds
Scenarios:
initialize - Connect, initialize, list tools, close
tools_call - Connect, call add_numbers(a=5, b=3), close
sse-retry - Connect, call test_reconnection, close
elicitation-sep1034-client-defaults - Elicitation with default accept callback
auth/client-credentials-jwt - Client credentials with private_key_jwt
auth/client-credentials-basic - Client credentials with client_secret_basic
auth/* - Authorization code flow (default for auth scenarios)
"""
import asyncio
import json
import logging
import os
import sys
from collections.abc import Callable, Coroutine
from typing import Any, cast
from urllib.parse import parse_qs, urlparse
import httpx
from pydantic import AnyUrl
from mcp import ClientSession, types
from mcp.client.auth import OAuthClientProvider, TokenStorage
from mcp.client.auth.extensions.client_credentials import (
ClientCredentialsOAuthProvider,
PrivateKeyJWTOAuthProvider,
SignedJWTParameters,
)
from mcp.client.context import ClientRequestContext
from mcp.client.streamable_http import streamable_http_client
from mcp.shared.auth import OAuthClientInformationFull, OAuthClientMetadata, OAuthToken
# Set up logging to stderr (stdout is for conformance test output)
logging.basicConfig(
level=logging.DEBUG,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
stream=sys.stderr,
)
logger = logging.getLogger(__name__)
# Type for async scenario handler functions
ScenarioHandler = Callable[[str], Coroutine[Any, None, None]]
# Registry of scenario handlers
HANDLERS: dict[str, ScenarioHandler] = {}
def register(name: str) -> Callable[[ScenarioHandler], ScenarioHandler]:
"""Register a scenario handler."""
def decorator(fn: ScenarioHandler) -> ScenarioHandler:
HANDLERS[name] = fn
return fn
return decorator
def get_conformance_context() -> dict[str, Any]:
"""Load conformance test context from MCP_CONFORMANCE_CONTEXT environment variable."""
context_json = os.environ.get("MCP_CONFORMANCE_CONTEXT")
if not context_json:
raise RuntimeError(
"MCP_CONFORMANCE_CONTEXT environment variable not set. "
"Expected JSON with client_id, client_secret, and/or private_key_pem."
)
try:
return json.loads(context_json)
except json.JSONDecodeError as e:
raise RuntimeError(f"Failed to parse MCP_CONFORMANCE_CONTEXT as JSON: {e}") from e
class InMemoryTokenStorage(TokenStorage):
"""Simple in-memory token storage for conformance testing."""
def __init__(self) -> None:
self._tokens: OAuthToken | None = None
self._client_info: OAuthClientInformationFull | None = None
async def get_tokens(self) -> OAuthToken | None:
return self._tokens
async def set_tokens(self, tokens: OAuthToken) -> None:
self._tokens = tokens
async def get_client_info(self) -> OAuthClientInformationFull | None:
return self._client_info
async def set_client_info(self, client_info: OAuthClientInformationFull) -> None:
self._client_info = client_info
class ConformanceOAuthCallbackHandler:
"""OAuth callback handler that automatically fetches the authorization URL
and extracts the auth code, without requiring user interaction.
"""
def __init__(self) -> None:
self._auth_code: str | None = None
self._state: str | None = None
async def handle_redirect(self, authorization_url: str) -> None:
"""Fetch the authorization URL and extract the auth code from the redirect."""
logger.debug(f"Fetching authorization URL: {authorization_url}")
async with httpx.AsyncClient() as client:
response = await client.get(
authorization_url,
follow_redirects=False,
)
if response.status_code in (301, 302, 303, 307, 308):
location = cast(str, response.headers.get("location"))
if location:
redirect_url = urlparse(location)
query_params: dict[str, list[str]] = parse_qs(redirect_url.query)
if "code" in query_params:
self._auth_code = query_params["code"][0]
state_values = query_params.get("state")
self._state = state_values[0] if state_values else None
logger.debug(f"Got auth code from redirect: {self._auth_code[:10]}...")
return
else:
raise RuntimeError(f"No auth code in redirect URL: {location}")
else:
raise RuntimeError(f"No redirect location received from {authorization_url}")
else:
raise RuntimeError(f"Expected redirect response, got {response.status_code} from {authorization_url}")
async def handle_callback(self) -> tuple[str, str | None]:
"""Return the captured auth code and state."""
if self._auth_code is None:
raise RuntimeError("No authorization code available - was handle_redirect called?")
auth_code = self._auth_code
state = self._state
self._auth_code = None
self._state = None
return auth_code, state
# --- Scenario Handlers ---
@register("initialize")
async def run_initialize(server_url: str) -> None:
"""Connect, initialize, list tools, close."""
async with streamable_http_client(url=server_url) as (read_stream, write_stream):
async with ClientSession(read_stream, write_stream) as session:
await session.initialize()
logger.debug("Initialized successfully")
await session.list_tools()
logger.debug("Listed tools successfully")
@register("tools_call")
async def run_tools_call(server_url: str) -> None:
"""Connect, initialize, list tools, call add_numbers(a=5, b=3), close."""
async with streamable_http_client(url=server_url) as (read_stream, write_stream):
async with ClientSession(read_stream, write_stream) as session:
await session.initialize()
await session.list_tools()
result = await session.call_tool("add_numbers", {"a": 5, "b": 3})
logger.debug(f"add_numbers result: {result}")
@register("sse-retry")
async def run_sse_retry(server_url: str) -> None:
"""Connect, initialize, list tools, call test_reconnection, close."""
async with streamable_http_client(url=server_url) as (read_stream, write_stream):
async with ClientSession(read_stream, write_stream) as session:
await session.initialize()
await session.list_tools()
result = await session.call_tool("test_reconnection", {})
logger.debug(f"test_reconnection result: {result}")
async def default_elicitation_callback(
context: ClientRequestContext,
params: types.ElicitRequestParams,
) -> types.ElicitResult | types.ErrorData:
"""Accept elicitation and apply defaults from the schema (SEP-1034)."""
content: dict[str, str | int | float | bool | list[str] | None] = {}
# For form mode, extract defaults from the requested_schema
if isinstance(params, types.ElicitRequestFormParams):
schema = params.requested_schema
logger.debug(f"Elicitation schema: {schema}")
properties = schema.get("properties", {})
for prop_name, prop_schema in properties.items():
if "default" in prop_schema:
content[prop_name] = prop_schema["default"]
logger.debug(f"Applied defaults: {content}")
return types.ElicitResult(action="accept", content=content)
@register("elicitation-sep1034-client-defaults")
async def run_elicitation_defaults(server_url: str) -> None:
"""Connect with elicitation callback that applies schema defaults."""
async with streamable_http_client(url=server_url) as (read_stream, write_stream):
async with ClientSession(
read_stream, write_stream, elicitation_callback=default_elicitation_callback
) as session:
await session.initialize()
await session.list_tools()
result = await session.call_tool("test_client_elicitation_defaults", {})
logger.debug(f"test_client_elicitation_defaults result: {result}")
@register("auth/client-credentials-jwt")
async def run_client_credentials_jwt(server_url: str) -> None:
"""Client credentials flow with private_key_jwt authentication."""
context = get_conformance_context()
client_id = context.get("client_id")
private_key_pem = context.get("private_key_pem")
signing_algorithm = context.get("signing_algorithm", "ES256")
if not client_id:
raise RuntimeError("MCP_CONFORMANCE_CONTEXT missing 'client_id'")
if not private_key_pem:
raise RuntimeError("MCP_CONFORMANCE_CONTEXT missing 'private_key_pem'")
jwt_params = SignedJWTParameters(
issuer=client_id,
subject=client_id,
signing_algorithm=signing_algorithm,
signing_key=private_key_pem,
)
oauth_auth = PrivateKeyJWTOAuthProvider(
server_url=server_url,
storage=InMemoryTokenStorage(),
client_id=client_id,
assertion_provider=jwt_params.create_assertion_provider(),
)
await _run_auth_session(server_url, oauth_auth)
@register("auth/client-credentials-basic")
async def run_client_credentials_basic(server_url: str) -> None:
"""Client credentials flow with client_secret_basic authentication."""
context = get_conformance_context()
client_id = context.get("client_id")
client_secret = context.get("client_secret")
if not client_id:
raise RuntimeError("MCP_CONFORMANCE_CONTEXT missing 'client_id'")
if not client_secret:
raise RuntimeError("MCP_CONFORMANCE_CONTEXT missing 'client_secret'")
oauth_auth = ClientCredentialsOAuthProvider(
server_url=server_url,
storage=InMemoryTokenStorage(),
client_id=client_id,
client_secret=client_secret,
token_endpoint_auth_method="client_secret_basic",
)
await _run_auth_session(server_url, oauth_auth)
async def run_auth_code_client(server_url: str) -> None:
"""Authorization code flow (default for auth/* scenarios)."""
callback_handler = ConformanceOAuthCallbackHandler()
storage = InMemoryTokenStorage()
# Check for pre-registered client credentials from context
context_json = os.environ.get("MCP_CONFORMANCE_CONTEXT")
if context_json:
try:
context = json.loads(context_json)
client_id = context.get("client_id")
client_secret = context.get("client_secret")
if client_id:
await storage.set_client_info(
OAuthClientInformationFull(
client_id=client_id,
client_secret=client_secret,
redirect_uris=[AnyUrl("http://localhost:3000/callback")],
token_endpoint_auth_method="client_secret_basic" if client_secret else "none",
)
)
logger.debug(f"Pre-loaded client credentials: client_id={client_id}")
except json.JSONDecodeError:
logger.exception("Failed to parse MCP_CONFORMANCE_CONTEXT")
oauth_auth = OAuthClientProvider(
server_url=server_url,
client_metadata=OAuthClientMetadata(
client_name="conformance-client",
redirect_uris=[AnyUrl("http://localhost:3000/callback")],
grant_types=["authorization_code", "refresh_token"],
response_types=["code"],
),
storage=storage,
redirect_handler=callback_handler.handle_redirect,
callback_handler=callback_handler.handle_callback,
client_metadata_url="https://conformance-test.local/client-metadata.json",
)
await _run_auth_session(server_url, oauth_auth)
async def _run_auth_session(server_url: str, oauth_auth: OAuthClientProvider) -> None:
"""Common session logic for all OAuth flows."""
client = httpx.AsyncClient(auth=oauth_auth, timeout=30.0)
async with streamable_http_client(url=server_url, http_client=client) as (read_stream, write_stream):
async with ClientSession(
read_stream, write_stream, elicitation_callback=default_elicitation_callback
) as session:
await session.initialize()
logger.debug("Initialized successfully")
tools_result = await session.list_tools()
logger.debug(f"Listed tools: {[t.name for t in tools_result.tools]}")
# Call the first available tool (different tests have different tools)
if tools_result.tools:
tool_name = tools_result.tools[0].name
try:
result = await session.call_tool(tool_name, {})
logger.debug(f"Called {tool_name}, result: {result}")
except Exception as e:
logger.debug(f"Tool call result/error: {e}")
logger.debug("Connection closed successfully")
def main() -> None:
"""Main entry point for the conformance client."""
if len(sys.argv) < 2:
print(f"Usage: {sys.argv[0]} <server-url>", file=sys.stderr)
sys.exit(1)
server_url = sys.argv[1]
scenario = os.environ.get("MCP_CONFORMANCE_SCENARIO")
if scenario:
logger.debug(f"Running explicit scenario '{scenario}' against {server_url}")
handler = HANDLERS.get(scenario)
if handler:
asyncio.run(handler(server_url))
elif scenario.startswith("auth/"):
asyncio.run(run_auth_code_client(server_url))
else:
print(f"Unknown scenario: {scenario}", file=sys.stderr)
sys.exit(1)
else:
logger.debug(f"Running default auth flow against {server_url}")
asyncio.run(run_auth_code_client(server_url))
if __name__ == "__main__":
main()
================================================
FILE: .github/actions/conformance/run-server.sh
================================================
#!/bin/bash
set -e
PORT="${PORT:-3001}"
SERVER_URL="http://localhost:${PORT}/mcp"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR/../../.."
# Start everything-server
uv run --frozen mcp-everything-server --port "$PORT" &
SERVER_PID=$!
trap "kill $SERVER_PID 2>/dev/null || true; wait $SERVER_PID 2>/dev/null || true" EXIT
# Wait for server to be ready
MAX_RETRIES=30
RETRY_COUNT=0
while ! curl -s "$SERVER_URL" > /dev/null 2>&1; do
RETRY_COUNT=$((RETRY_COUNT + 1))
if [ $RETRY_COUNT -ge $MAX_RETRIES ]; then
echo "Server failed to start after ${MAX_RETRIES} retries" >&2
exit 1
fi
sleep 0.5
done
echo "Server ready at $SERVER_URL"
# Run conformance tests
npx @modelcontextprotocol/conformance@0.1.10 server --url "$SERVER_URL" "$@"
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: monthly
groups:
github-actions:
patterns:
- "*"
================================================
FILE: .github/workflows/claude-code-review.yml
================================================
# Source: https://github.com/anthropics/claude-code-action/blob/main/docs/code-review.md
name: Claude Code Review
on:
pull_request:
types: [opened, synchronize, ready_for_review, reopened]
jobs:
claude-review:
# Fork PRs don't have access to secrets or OIDC tokens, so the action
# cannot authenticate. See https://github.com/anthropics/claude-code-action/issues/339
if: github.event.pull_request.head.repo.fork == false && github.actor != 'dependabot[bot]'
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
issues: read
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 1
- name: Run Claude Code Review
id: claude-review
uses: anthropics/claude-code-action@2f8ba26a219c06cfb0f468eef8d97055fa814f97 # v1.0.53
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
plugin_marketplaces: "https://github.com/anthropics/claude-code.git"
plugins: "code-review@claude-code-plugins"
prompt: "/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }}"
================================================
FILE: .github/workflows/claude.yml
================================================
# Source: https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
name: Claude Code
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [opened, assigned]
pull_request_review:
types: [submitted]
jobs:
claude:
if: |
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
issues: read
id-token: write
actions: read # Required for Claude to read CI results on PRs
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 1
- name: Run Claude Code
id: claude
uses: anthropics/claude-code-action@2f8ba26a219c06cfb0f468eef8d97055fa814f97 # v1.0.53
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
use_commit_signing: true
additional_permissions: |
actions: read
================================================
FILE: .github/workflows/comment-on-release.yml
================================================
name: Comment on PRs in Release
on:
release:
types: [published]
permissions:
pull-requests: write
contents: read
jobs:
comment-on-prs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
fetch-depth: 0
- name: Get previous release
id: previous_release
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
const currentTag = '${{ github.event.release.tag_name }}';
// Get all releases
const { data: releases } = await github.rest.repos.listReleases({
owner: context.repo.owner,
repo: context.repo.repo,
per_page: 100
});
// Find current release index
const currentIndex = releases.findIndex(r => r.tag_name === currentTag);
if (currentIndex === -1) {
console.log('Current release not found in list');
return null;
}
// Get previous release (next in the list since they're sorted by date desc)
const previousRelease = releases[currentIndex + 1];
if (!previousRelease) {
console.log('No previous release found, this might be the first release');
return null;
}
console.log(`Found previous release: ${previousRelease.tag_name}`);
return previousRelease.tag_name;
- name: Get merged PRs between releases
id: get_prs
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
const currentTag = '${{ github.event.release.tag_name }}';
const previousTag = ${{ steps.previous_release.outputs.result }};
if (!previousTag) {
console.log('No previous release found, skipping');
return [];
}
console.log(`Finding PRs between ${previousTag} and ${currentTag}`);
// Get commits between previous and current release
const comparison = await github.rest.repos.compareCommits({
owner: context.repo.owner,
repo: context.repo.repo,
base: previousTag,
head: currentTag
});
const commits = comparison.data.commits;
console.log(`Found ${commits.length} commits`);
// Get PRs associated with each commit using GitHub API
const prNumbers = new Set();
for (const commit of commits) {
try {
const { data: prs } = await github.rest.repos.listPullRequestsAssociatedWithCommit({
owner: context.repo.owner,
repo: context.repo.repo,
commit_sha: commit.sha
});
for (const pr of prs) {
if (pr.merged_at) {
prNumbers.add(pr.number);
console.log(`Found merged PR: #${pr.number}`);
}
}
} catch (error) {
console.log(`Failed to get PRs for commit ${commit.sha}: ${error.message}`);
}
}
console.log(`Found ${prNumbers.size} merged PRs`);
return Array.from(prNumbers);
- name: Comment on PRs
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
const prNumbers = ${{ steps.get_prs.outputs.result }};
const releaseTag = '${{ github.event.release.tag_name }}';
const releaseUrl = '${{ github.event.release.html_url }}';
const comment = `This pull request is included in [${releaseTag}](${releaseUrl})`;
let commentedCount = 0;
for (const prNumber of prNumbers) {
try {
// Check if we've already commented on this PR for this release
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
per_page: 100
});
const alreadyCommented = comments.some(c =>
c.user.type === 'Bot' && c.body.includes(releaseTag)
);
if (alreadyCommented) {
console.log(`Skipping PR #${prNumber} - already commented for ${releaseTag}`);
continue;
}
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: comment
});
commentedCount++;
console.log(`Successfully commented on PR #${prNumber}`);
} catch (error) {
console.error(`Failed to comment on PR #${prNumber}:`, error.message);
}
}
console.log(`Commented on ${commentedCount} of ${prNumbers.length} PRs`);
================================================
FILE: .github/workflows/conformance.yml
================================================
name: Conformance Tests
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
concurrency:
group: conformance-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
server-conformance:
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1
with:
enable-cache: true
version: 0.9.5
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: 24
- run: uv sync --frozen --all-extras --package mcp-everything-server
- run: ./.github/actions/conformance/run-server.sh
client-conformance:
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1
with:
enable-cache: true
version: 0.9.5
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: 24
- run: uv sync --frozen --all-extras --package mcp
- run: npx @modelcontextprotocol/conformance@0.1.13 client --command 'uv run --frozen python .github/actions/conformance/client.py' --suite all
================================================
FILE: .github/workflows/main.yml
================================================
name: CI
on:
push:
branches: ["main", "v1.x"]
tags: ["v*.*.*"]
pull_request:
branches: ["main", "v1.x"]
permissions:
contents: read
jobs:
checks:
uses: ./.github/workflows/shared.yml
all-green:
if: always()
needs: [checks]
runs-on: ubuntu-latest
steps:
- uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2
with:
jobs: ${{ toJSON(needs) }}
================================================
FILE: .github/workflows/publish-docs-manually.yml
================================================
name: Publish Docs manually
on:
workflow_dispatch:
jobs:
docs-publish:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- name: Configure Git Credentials
run: |
git config user.name github-actions[bot]
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
- name: Install uv
uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1
with:
enable-cache: true
version: 0.9.5
- run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
- uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
with:
key: mkdocs-material-${{ env.cache_id }}
path: .cache
restore-keys: |
mkdocs-material-
- run: uv sync --frozen --group docs
- run: uv run --frozen --no-sync mkdocs gh-deploy --force
env:
ENABLE_SOCIAL_CARDS: "true"
================================================
FILE: .github/workflows/publish-pypi.yml
================================================
name: Publishing
on:
release:
types: [published]
jobs:
release-build:
name: Build distribution
runs-on: ubuntu-latest
needs: [checks]
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- name: Install uv
uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1
with:
enable-cache: true
version: 0.9.5
- name: Set up Python 3.12
run: uv python install 3.12
- name: Build
run: uv build
- name: Upload artifacts
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: release-dists
path: dist/
checks:
uses: ./.github/workflows/shared.yml
pypi-publish:
name: Upload release to PyPI
runs-on: ubuntu-latest
environment: release
needs:
- release-build
permissions:
id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
steps:
- name: Retrieve release distributions
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
name: release-dists
path: dist/
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # release/v1
docs-publish:
runs-on: ubuntu-latest
needs: ["pypi-publish"]
permissions:
contents: write
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- name: Configure Git Credentials
run: |
git config user.name github-actions[bot]
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
- name: Install uv
uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1
with:
enable-cache: true
version: 0.9.5
- run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
- uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
with:
key: mkdocs-material-${{ env.cache_id }}
path: .cache
restore-keys: |
mkdocs-material-
- run: uv sync --frozen --group docs
- run: uv run --frozen --no-sync mkdocs gh-deploy --force
================================================
FILE: .github/workflows/shared.yml
================================================
name: Shared Checks
on:
workflow_call:
permissions:
contents: read
env:
COLUMNS: 150
jobs:
pre-commit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1
with:
enable-cache: true
version: 0.9.5
- name: Install dependencies
run: uv sync --frozen --all-extras --python 3.10
- uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1
with:
extra_args: --all-files --verbose
env:
SKIP: no-commit-to-branch,readme-v1-frozen
# TODO(Max): Drop this in v2.
- name: Check README.md is not modified
if: github.event_name == 'pull_request'
run: |
git fetch --no-tags --depth=1 origin "$BASE_SHA"
if git diff --name-only "$BASE_SHA" -- README.md | grep -q .; then
echo "::error::README.md is frozen at v1. Edit README.v2.md instead."
exit 1
fi
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
test:
name: test (${{ matrix.python-version }}, ${{ matrix.dep-resolution.name }}, ${{ matrix.os }})
runs-on: ${{ matrix.os }}
timeout-minutes: 10
continue-on-error: true
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
dep-resolution:
- name: lowest-direct
install-flags: "--upgrade --resolution lowest-direct"
- name: locked
install-flags: "--frozen"
os: [ubuntu-latest, windows-latest]
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- name: Install uv
uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1
with:
enable-cache: true
version: 0.9.5
- name: Install the project
run: uv sync ${{ matrix.dep-resolution.install-flags }} --all-extras --python ${{ matrix.python-version }}
- name: Run pytest with coverage
shell: bash
run: |
uv run --frozen --no-sync coverage erase
uv run --frozen --no-sync coverage run -m pytest -n auto
uv run --frozen --no-sync coverage combine
uv run --frozen --no-sync coverage report
- name: Check for unnecessary no cover pragmas
if: runner.os != 'Windows'
run: uv run --frozen --no-sync strict-no-cover
readme-snippets:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1
with:
enable-cache: true
version: 0.9.5
- name: Install dependencies
run: uv sync --frozen --all-extras --python 3.10
- name: Check README snippets are up to date
run: uv run --frozen scripts/update_readme_snippets.py --check --readme README.v2.md
================================================
FILE: .github/workflows/weekly-lockfile-update.yml
================================================
name: Weekly Lockfile Update
on:
workflow_dispatch:
schedule:
# Every Thursday at 8:00 UTC
- cron: "0 8 * * 4"
permissions:
contents: write
pull-requests: write
jobs:
update-lockfile:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1
with:
version: 0.9.5
- name: Update lockfile
run: |
echo '## Updated Dependencies' > pr_body.md
echo '' >> pr_body.md
echo '```' >> pr_body.md
uv lock --upgrade 2>&1 | tee -a pr_body.md
echo '```' >> pr_body.md
- name: Create pull request
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7
with:
commit-message: "chore: update uv.lock with latest dependencies"
sign-commits: true
title: "chore: weekly dependency update"
body-path: pr_body.md
branch: weekly-lockfile-update
delete-branch: true
add-paths: uv.lock
labels: dependencies
================================================
FILE: .gitignore
================================================
.DS_Store
scratch/
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
.ruff_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
.pdm.toml
.pdm-python
.pdm-build/
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
.idea/
# vscode
.vscode/
.windsurfrules
**/CLAUDE.local.md
# claude code
results/
================================================
FILE: .pre-commit-config.yaml
================================================
fail_fast: true
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: end-of-file-fixer
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v3.1.0
hooks:
- id: prettier
types_or: [yaml, json5]
- repo: https://github.com/igorshubovych/markdownlint-cli
rev: v0.45.0
hooks:
- id: markdownlint
args:
[
"--fix",
"--config",
"pyproject.toml",
"--configPointer",
"/tool/markdown/lint",
]
types: [markdown]
- repo: local
hooks:
- id: ruff-format
name: Ruff Format
entry: uv run --frozen ruff
args: [format]
language: system
types: [python]
pass_filenames: false
- id: ruff
name: Ruff
entry: uv run --frozen ruff
args: ["check", "--fix", "--exit-non-zero-on-fix"]
types: [python]
language: system
pass_filenames: false
exclude: ^README(\.v2)?\.md$
- id: pyright
name: pyright
entry: uv run --frozen pyright
language: system
types: [python]
pass_filenames: false
- id: uv-lock-check
name: Check uv.lock is up to date
entry: uv lock --check
language: system
files: ^(pyproject\.toml|uv\.lock)$
pass_filenames: false
# TODO(Max): Drop this in v2.
- id: readme-v1-frozen
name: README.md is frozen (v1 docs)
entry: README.md is frozen at v1. Edit README.v2.md instead.
language: fail
files: ^README\.md$
- id: readme-snippets
name: Check README snippets are up to date
entry: uv run --frozen python scripts/update_readme_snippets.py --check
language: system
files: ^(README\.v2\.md|examples/.*\.py|scripts/update_readme_snippets\.py)$
pass_filenames: false
================================================
FILE: CLAUDE.md
================================================
# Development Guidelines
This document contains critical information about working with this codebase. Follow these guidelines precisely.
## Core Development Rules
1. Package Management
- ONLY use uv, NEVER pip
- Installation: `uv add <package>`
- Running tools: `uv run <tool>`
- Upgrading: `uv lock --upgrade-package <package>`
- FORBIDDEN: `uv pip install`, `@latest` syntax
2. Code Quality
- Type hints required for all code
- Public APIs must have docstrings
- Functions must be focused and small
- Follow existing patterns exactly
- Line length: 120 chars maximum
- FORBIDDEN: imports inside functions. THEY SHOULD BE AT THE TOP OF THE FILE.
3. Testing Requirements
- Framework: `uv run --frozen pytest`
- Async testing: use anyio, not asyncio
- Do not use `Test` prefixed classes, use functions
- Coverage: test edge cases and errors
- New features require tests
- Bug fixes require regression tests
- IMPORTANT: The `tests/client/test_client.py` is the most well designed test file. Follow its patterns.
- IMPORTANT: Be minimal, and focus on E2E tests: Use the `mcp.client.Client` whenever possible.
- Coverage: CI requires 100% (`fail_under = 100`, `branch = true`).
- Full check: `./scripts/test` (~23s). Runs coverage + `strict-no-cover` on the
default Python. Not identical to CI: CI also runs 3.10–3.14 × {ubuntu, windows},
and some branch-coverage quirks only surface on specific matrix entries.
- Targeted check while iterating (~4s, deterministic):
```bash
uv run --frozen coverage erase
uv run --frozen coverage run -m pytest tests/path/test_foo.py
uv run --frozen coverage combine
uv run --frozen coverage report --include='src/mcp/path/foo.py' --fail-under=0
UV_FROZEN=1 uv run --frozen strict-no-cover
```
Partial runs can't hit 100% (coverage tracks `tests/` too), so `--fail-under=0`
and `--include` scope the report. `strict-no-cover` has no false positives on
partial runs — if your new test executes a line marked `# pragma: no cover`,
even a single-file run catches it.
- Coverage pragmas:
- `# pragma: no cover` — line is never executed. CI's `strict-no-cover` fails if
it IS executed. When your test starts covering such a line, remove the pragma.
- `# pragma: lax no cover` — excluded from coverage but not checked by
`strict-no-cover`. Use for lines covered on some platforms/versions but not
others.
- `# pragma: no branch` — excludes branch arcs only. coverage.py misreports the
`->exit` arc for nested `async with` on Python 3.11+ (worse on 3.14/Windows).
- Avoid `anyio.sleep()` with a fixed duration to wait for async operations. Instead:
- Use `anyio.Event` — set it in the callback/handler, `await event.wait()` in the test
- For stream messages, use `await stream.receive()` instead of `sleep()` + `receive_nowait()`
- Exception: `sleep()` is appropriate when testing time-based features (e.g., timeouts)
- Wrap indefinite waits (`event.wait()`, `stream.receive()`) in `anyio.fail_after(5)` to prevent hangs
Test files mirror the source tree: `src/mcp/client/streamable_http.py` → `tests/client/test_streamable_http.py`
Add tests to the existing file for that module.
- For commits fixing bugs or adding features based on user reports add:
```bash
git commit --trailer "Reported-by:<name>"
```
Where `<name>` is the name of the user.
- For commits related to a Github issue, add
```bash
git commit --trailer "Github-Issue:#<number>"
```
- NEVER ever mention a `co-authored-by` or similar aspects. In particular, never
mention the tool used to create the commit message or PR.
## Pull Requests
- Create a detailed message of what changed. Focus on the high level description of
the problem it tries to solve, and how it is solved. Don't go into the specifics of the
code unless it adds clarity.
- NEVER ever mention a `co-authored-by` or similar aspects. In particular, never
mention the tool used to create the commit message or PR.
## Breaking Changes
When making breaking changes, document them in `docs/migration.md`. Include:
- What changed
- Why it changed
- How to migrate existing code
Search for related sections in the migration guide and group related changes together
rather than adding new standalone sections.
## Python Tools
## Code Formatting
1. Ruff
- Format: `uv run --frozen ruff format .`
- Check: `uv run --frozen ruff check .`
- Fix: `uv run --frozen ruff check . --fix`
- Critical issues:
- Line length (88 chars)
- Import sorting (I001)
- Unused imports
- Line wrapping:
- Strings: use parentheses
- Function calls: multi-line with proper indent
- Imports: try to use a single line
2. Type Checking
- Tool: `uv run --frozen pyright`
- Requirements:
- Type narrowing for strings
- Version warnings can be ignored if checks pass
3. Pre-commit
- Config: `.pre-commit-config.yaml`
- Runs: on git commit
- Tools: Prettier (YAML/JSON), Ruff (Python)
- Ruff updates:
- Check PyPI versions
- Update config rev
- Commit config first
## Error Resolution
1. CI Failures
- Fix order:
1. Formatting
2. Type errors
3. Linting
- Type errors:
- Get full line context
- Check Optional types
- Add type narrowing
- Verify function signatures
2. Common Issues
- Line length:
- Break strings with parentheses
- Multi-line function calls
- Split imports
- Types:
- Add None checks
- Narrow string types
- Match existing patterns
3. Best Practices
- Check git status before commits
- Run formatters before type checks
- Keep changes minimal
- Follow existing patterns
- Document public APIs
- Test thoroughly
## Exception Handling
- **Always use `logger.exception()` instead of `logger.error()` when catching exceptions**
- Don't include the exception in the message: `logger.exception("Failed")` not `logger.exception(f"Failed: {e}")`
- **Catch specific exceptions** where possible:
- File ops: `except (OSError, PermissionError):`
- JSON: `except json.JSONDecodeError:`
- Network: `except (ConnectionError, TimeoutError):`
- **FORBIDDEN** `except Exception:` - unless in top-level handlers
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
<mcp-coc@anthropic.com>.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
<https://www.contributor-covenant.org/version/2/0/code_of_conduct.html>.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
<https://www.contributor-covenant.org/faq>. Translations are available at
<https://www.contributor-covenant.org/translations>.
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing
Thank you for your interest in contributing to the MCP Python SDK! This document provides guidelines and instructions for contributing.
## Before You Start
We welcome contributions! These guidelines exist to save everyone time, yours included. Following them means your work is more likely to be accepted.
**All pull requests require a corresponding issue.** Unless your change is trivial (typo, docs tweak, broken link), create an issue first. Every merged feature becomes ongoing maintenance, so we need to agree something is worth doing before reviewing code. PRs without a linked issue will be closed.
Having an issue doesn't guarantee acceptance. Wait for maintainer feedback or a `ready for work` label before starting. PRs for issues without buy-in may also be closed.
Use issues to validate your idea before investing time in code. PRs are for execution, not exploration.
### The SDK is Opinionated
Not every contribution will be accepted, even with a working implementation. We prioritize maintainability and consistency over adding capabilities. This is at maintainers' discretion.
### What Needs Discussion
These always require an issue first:
- New public APIs or decorators
- Architectural changes or refactoring
- Changes that touch multiple modules
- Features that might require spec changes (these need a [SEP](https://github.com/modelcontextprotocol/modelcontextprotocol) first)
Bug fixes for clear, reproducible issues are welcome—but still create an issue to track the fix.
### Finding Issues to Work On
| Label | For | Description |
|-------|-----|-------------|
| [`good first issue`](https://github.com/modelcontextprotocol/python-sdk/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) | Newcomers | Can tackle without deep codebase knowledge |
| [`help wanted`](https://github.com/modelcontextprotocol/python-sdk/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22) | Experienced contributors | Maintainers probably won't get to this |
| [`ready for work`](https://github.com/modelcontextprotocol/python-sdk/issues?q=is%3Aopen+is%3Aissue+label%3A%22ready+for+work%22) | Maintainers | Triaged and ready for a maintainer to pick up |
Issues labeled `needs confirmation` or `needs maintainer action` are **not** ready for work—wait for maintainer input first.
Before starting, comment on the issue so we can assign it to you. This prevents duplicate effort.
## Development Setup
1. Make sure you have Python 3.10+ installed
2. Install [uv](https://docs.astral.sh/uv/getting-started/installation/)
3. Fork the repository
4. Clone your fork: `git clone https://github.com/YOUR-USERNAME/python-sdk.git`
5. Install dependencies:
```bash
uv sync --frozen --all-extras --dev
```
6. Set up pre-commit hooks:
```bash
uv tool install pre-commit --with pre-commit-uv --force-reinstall
```
## Development Workflow
1. Choose the correct branch for your changes:
| Change Type | Target Branch | Example |
|-------------|---------------|---------|
| New features, breaking changes | `main` | New APIs, refactors |
| Security fixes for v1 | `v1.x` | Critical patches |
| Bug fixes for v1 | `v1.x` | Non-breaking fixes |
> **Note:** `main` is the v2 development branch. Breaking changes are welcome on `main`. The `v1.x` branch receives only security and critical bug fixes.
2. Create a new branch from your chosen base branch
3. Make your changes
4. Ensure tests pass:
```bash
uv run pytest
```
5. Run type checking:
```bash
uv run pyright
```
6. Run linting:
```bash
uv run ruff check .
uv run ruff format .
```
7. Update README snippets if you modified example code:
```bash
uv run scripts/update_readme_snippets.py
```
8. (Optional) Run pre-commit hooks on all files:
```bash
pre-commit run --all-files
```
9. Submit a pull request to the same branch you branched from
## Code Style
- We use `ruff` for linting and formatting
- Follow PEP 8 style guidelines
- Add type hints to all functions
- Include docstrings for public APIs
## Pull Requests
By the time you open a PR, the "what" and "why" should already be settled in an issue. This keeps reviews focused on implementation.
### Scope
Small PRs get reviewed fast. Large PRs sit in the queue.
A few dozen lines can be reviewed in minutes. Hundreds of lines across many files takes real effort and things slip through. If your change is big, break it into smaller PRs or get alignment from a maintainer first.
### What Gets Rejected
- **No prior discussion**: Features or significant changes without an approved issue
- **Scope creep**: Changes that go beyond what was discussed
- **Misalignment**: Even well-implemented features may be rejected if they don't fit the SDK's direction
- **Overengineering**: Unnecessary complexity for simple problems
### Checklist
1. Update documentation as needed
2. Add tests for new functionality
3. Ensure CI passes
4. Address review feedback
## Code of Conduct
Please note that this project is released with a [Code of Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms.
## License
By contributing, you agree that your contributions will be licensed under the MIT License.
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2024 Anthropic, PBC
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# MCP Python SDK
<div align="center">
<strong>Python implementation of the Model Context Protocol (MCP)</strong>
[![PyPI][pypi-badge]][pypi-url]
[![MIT licensed][mit-badge]][mit-url]
[![Python Version][python-badge]][python-url]
[![Documentation][docs-badge]][docs-url]
[![Protocol][protocol-badge]][protocol-url]
[![Specification][spec-badge]][spec-url]
</div>
<!-- TODO(v2): Replace this README with README.v2.md when v2 is released -->
> [!NOTE]
> **This README documents v1.x of the MCP Python SDK (the current stable release).**
>
> For v1.x code and documentation, see the [`v1.x` branch](https://github.com/modelcontextprotocol/python-sdk/tree/v1.x).
> For the upcoming v2 documentation (pre-alpha, in development on `main`), see [`README.v2.md`](README.v2.md).
<!-- omit in toc -->
## Table of Contents
- [MCP Python SDK](#mcp-python-sdk)
- [Overview](#overview)
- [Installation](#installation)
- [Adding MCP to your python project](#adding-mcp-to-your-python-project)
- [Running the standalone MCP development tools](#running-the-standalone-mcp-development-tools)
- [Quickstart](#quickstart)
- [What is MCP?](#what-is-mcp)
- [Core Concepts](#core-concepts)
- [Server](#server)
- [Resources](#resources)
- [Tools](#tools)
- [Structured Output](#structured-output)
- [Prompts](#prompts)
- [Images](#images)
- [Context](#context)
- [Getting Context in Functions](#getting-context-in-functions)
- [Context Properties and Methods](#context-properties-and-methods)
- [Completions](#completions)
- [Elicitation](#elicitation)
- [Sampling](#sampling)
- [Logging and Notifications](#logging-and-notifications)
- [Authentication](#authentication)
- [FastMCP Properties](#fastmcp-properties)
- [Session Properties and Methods](#session-properties-and-methods)
- [Request Context Properties](#request-context-properties)
- [Running Your Server](#running-your-server)
- [Development Mode](#development-mode)
- [Claude Desktop Integration](#claude-desktop-integration)
- [Direct Execution](#direct-execution)
- [Streamable HTTP Transport](#streamable-http-transport)
- [CORS Configuration for Browser-Based Clients](#cors-configuration-for-browser-based-clients)
- [Mounting to an Existing ASGI Server](#mounting-to-an-existing-asgi-server)
- [StreamableHTTP servers](#streamablehttp-servers)
- [Basic mounting](#basic-mounting)
- [Host-based routing](#host-based-routing)
- [Multiple servers with path configuration](#multiple-servers-with-path-configuration)
- [Path configuration at initialization](#path-configuration-at-initialization)
- [SSE servers](#sse-servers)
- [Advanced Usage](#advanced-usage)
- [Low-Level Server](#low-level-server)
- [Structured Output Support](#structured-output-support)
- [Pagination (Advanced)](#pagination-advanced)
- [Writing MCP Clients](#writing-mcp-clients)
- [Client Display Utilities](#client-display-utilities)
- [OAuth Authentication for Clients](#oauth-authentication-for-clients)
- [Parsing Tool Results](#parsing-tool-results)
- [MCP Primitives](#mcp-primitives)
- [Server Capabilities](#server-capabilities)
- [Documentation](#documentation)
- [Contributing](#contributing)
- [License](#license)
[pypi-badge]: https://img.shields.io/pypi/v/mcp.svg
[pypi-url]: https://pypi.org/project/mcp/
[mit-badge]: https://img.shields.io/pypi/l/mcp.svg
[mit-url]: https://github.com/modelcontextprotocol/python-sdk/blob/main/LICENSE
[python-badge]: https://img.shields.io/pypi/pyversions/mcp.svg
[python-url]: https://www.python.org/downloads/
[docs-badge]: https://img.shields.io/badge/docs-python--sdk-blue.svg
[docs-url]: https://modelcontextprotocol.github.io/python-sdk/
[protocol-badge]: https://img.shields.io/badge/protocol-modelcontextprotocol.io-blue.svg
[protocol-url]: https://modelcontextprotocol.io
[spec-badge]: https://img.shields.io/badge/spec-spec.modelcontextprotocol.io-blue.svg
[spec-url]: https://modelcontextprotocol.io/specification/latest
## Overview
The Model Context Protocol allows applications to provide context for LLMs in a standardized way, separating the concerns of providing context from the actual LLM interaction. This Python SDK implements the full MCP specification, making it easy to:
- Build MCP clients that can connect to any MCP server
- Create MCP servers that expose resources, prompts and tools
- Use standard transports like stdio, SSE, and Streamable HTTP
- Handle all MCP protocol messages and lifecycle events
## Installation
### Adding MCP to your python project
We recommend using [uv](https://docs.astral.sh/uv/) to manage your Python projects.
If you haven't created a uv-managed project yet, create one:
```bash
uv init mcp-server-demo
cd mcp-server-demo
```
Then add MCP to your project dependencies:
```bash
uv add "mcp[cli]"
```
Alternatively, for projects using pip for dependencies:
```bash
pip install "mcp[cli]"
```
### Running the standalone MCP development tools
To run the mcp command with uv:
```bash
uv run mcp
```
## Quickstart
Let's create a simple MCP server that exposes a calculator tool and some data:
<!-- snippet-source examples/snippets/servers/fastmcp_quickstart.py -->
```python
"""
FastMCP quickstart example.
Run from the repository root:
uv run examples/snippets/servers/fastmcp_quickstart.py
"""
from mcp.server.fastmcp import FastMCP
# Create an MCP server
mcp = FastMCP("Demo", json_response=True)
# Add an addition tool
@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers"""
return a + b
# Add a dynamic greeting resource
@mcp.resource("greeting://{name}")
def get_greeting(name: str) -> str:
"""Get a personalized greeting"""
return f"Hello, {name}!"
# Add a prompt
@mcp.prompt()
def greet_user(name: str, style: str = "friendly") -> str:
"""Generate a greeting prompt"""
styles = {
"friendly": "Please write a warm, friendly greeting",
"formal": "Please write a formal, professional greeting",
"casual": "Please write a casual, relaxed greeting",
}
return f"{styles.get(style, styles['friendly'])} for someone named {name}."
# Run with streamable HTTP transport
if __name__ == "__main__":
mcp.run(transport="streamable-http")
```
_Full example: [examples/snippets/servers/fastmcp_quickstart.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/fastmcp_quickstart.py)_
<!-- /snippet-source -->
You can install this server in [Claude Code](https://docs.claude.com/en/docs/claude-code/mcp) and interact with it right away. First, run the server:
```bash
uv run --with mcp examples/snippets/servers/fastmcp_quickstart.py
```
Then add it to Claude Code:
```bash
claude mcp add --transport http my-server http://localhost:8000/mcp
```
Alternatively, you can test it with the MCP Inspector. Start the server as above, then in a separate terminal:
```bash
npx -y @modelcontextprotocol/inspector
```
In the inspector UI, connect to `http://localhost:8000/mcp`.
## What is MCP?
The [Model Context Protocol (MCP)](https://modelcontextprotocol.io) lets you build servers that expose data and functionality to LLM applications in a secure, standardized way. Think of it like a web API, but specifically designed for LLM interactions. MCP servers can:
- Expose data through **Resources** (think of these sort of like GET endpoints; they are used to load information into the LLM's context)
- Provide functionality through **Tools** (sort of like POST endpoints; they are used to execute code or otherwise produce a side effect)
- Define interaction patterns through **Prompts** (reusable templates for LLM interactions)
- And more!
## Core Concepts
### Server
The FastMCP server is your core interface to the MCP protocol. It handles connection management, protocol compliance, and message routing:
<!-- snippet-source examples/snippets/servers/lifespan_example.py -->
```python
"""Example showing lifespan support for startup/shutdown with strong typing."""
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from dataclasses import dataclass
from mcp.server.fastmcp import Context, FastMCP
from mcp.server.session import ServerSession
# Mock database class for example
class Database:
"""Mock database class for example."""
@classmethod
async def connect(cls) -> "Database":
"""Connect to database."""
return cls()
async def disconnect(self) -> None:
"""Disconnect from database."""
pass
def query(self) -> str:
"""Execute a query."""
return "Query result"
@dataclass
class AppContext:
"""Application context with typed dependencies."""
db: Database
@asynccontextmanager
async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]:
"""Manage application lifecycle with type-safe context."""
# Initialize on startup
db = await Database.connect()
try:
yield AppContext(db=db)
finally:
# Cleanup on shutdown
await db.disconnect()
# Pass lifespan to server
mcp = FastMCP("My App", lifespan=app_lifespan)
# Access type-safe lifespan context in tools
@mcp.tool()
def query_db(ctx: Context[ServerSession, AppContext]) -> str:
"""Tool that uses initialized resources."""
db = ctx.request_context.lifespan_context.db
return db.query()
```
_Full example: [examples/snippets/servers/lifespan_example.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/lifespan_example.py)_
<!-- /snippet-source -->
### Resources
Resources are how you expose data to LLMs. They're similar to GET endpoints in a REST API - they provide data but shouldn't perform significant computation or have side effects:
<!-- snippet-source examples/snippets/servers/basic_resource.py -->
```python
from mcp.server.fastmcp import FastMCP
mcp = FastMCP(name="Resource Example")
@mcp.resource("file://documents/{name}")
def read_document(name: str) -> str:
"""Read a document by name."""
# This would normally read from disk
return f"Content of {name}"
@mcp.resource("config://settings")
def get_settings() -> str:
"""Get application settings."""
return """{
"theme": "dark",
"language": "en",
"debug": false
}"""
```
_Full example: [examples/snippets/servers/basic_resource.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/basic_resource.py)_
<!-- /snippet-source -->
### Tools
Tools let LLMs take actions through your server. Unlike resources, tools are expected to perform computation and have side effects:
<!-- snippet-source examples/snippets/servers/basic_tool.py -->
```python
from mcp.server.fastmcp import FastMCP
mcp = FastMCP(name="Tool Example")
@mcp.tool()
def sum(a: int, b: int) -> int:
"""Add two numbers together."""
return a + b
@mcp.tool()
def get_weather(city: str, unit: str = "celsius") -> str:
"""Get weather for a city."""
# This would normally call a weather API
return f"Weather in {city}: 22degrees{unit[0].upper()}"
```
_Full example: [examples/snippets/servers/basic_tool.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/basic_tool.py)_
<!-- /snippet-source -->
Tools can optionally receive a Context object by including a parameter with the `Context` type annotation. This context is automatically injected by the FastMCP framework and provides access to MCP capabilities:
<!-- snippet-source examples/snippets/servers/tool_progress.py -->
```python
from mcp.server.fastmcp import Context, FastMCP
from mcp.server.session import ServerSession
mcp = FastMCP(name="Progress Example")
@mcp.tool()
async def long_running_task(task_name: str, ctx: Context[ServerSession, None], steps: int = 5) -> str:
"""Execute a task with progress updates."""
await ctx.info(f"Starting: {task_name}")
for i in range(steps):
progress = (i + 1) / steps
await ctx.report_progress(
progress=progress,
total=1.0,
message=f"Step {i + 1}/{steps}",
)
await ctx.debug(f"Completed step {i + 1}")
return f"Task '{task_name}' completed"
```
_Full example: [examples/snippets/servers/tool_progress.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/tool_progress.py)_
<!-- /snippet-source -->
#### Structured Output
Tools will return structured results by default, if their return type
annotation is compatible. Otherwise, they will return unstructured results.
Structured output supports these return types:
- Pydantic models (BaseModel subclasses)
- TypedDicts
- Dataclasses and other classes with type hints
- `dict[str, T]` (where T is any JSON-serializable type)
- Primitive types (str, int, float, bool, bytes, None) - wrapped in `{"result": value}`
- Generic types (list, tuple, Union, Optional, etc.) - wrapped in `{"result": value}`
Classes without type hints cannot be serialized for structured output. Only
classes with properly annotated attributes will be converted to Pydantic models
for schema generation and validation.
Structured results are automatically validated against the output schema
generated from the annotation. This ensures the tool returns well-typed,
validated data that clients can easily process.
**Note:** For backward compatibility, unstructured results are also
returned. Unstructured results are provided for backward compatibility
with previous versions of the MCP specification, and are quirks-compatible
with previous versions of FastMCP in the current version of the SDK.
**Note:** In cases where a tool function's return type annotation
causes the tool to be classified as structured _and this is undesirable_,
the classification can be suppressed by passing `structured_output=False`
to the `@tool` decorator.
##### Advanced: Direct CallToolResult
For full control over tool responses including the `_meta` field (for passing data to client applications without exposing it to the model), you can return `CallToolResult` directly:
<!-- snippet-source examples/snippets/servers/direct_call_tool_result.py -->
```python
"""Example showing direct CallToolResult return for advanced control."""
from typing import Annotated
from pydantic import BaseModel
from mcp.server.fastmcp import FastMCP
from mcp.types import CallToolResult, TextContent
mcp = FastMCP("CallToolResult Example")
class ValidationModel(BaseModel):
"""Model for validating structured output."""
status: str
data: dict[str, int]
@mcp.tool()
def advanced_tool() -> CallToolResult:
"""Return CallToolResult directly for full control including _meta field."""
return CallToolResult(
content=[TextContent(type="text", text="Response visible to the model")],
_meta={"hidden": "data for client applications only"},
)
@mcp.tool()
def validated_tool() -> Annotated[CallToolResult, ValidationModel]:
"""Return CallToolResult with structured output validation."""
return CallToolResult(
content=[TextContent(type="text", text="Validated response")],
structuredContent={"status": "success", "data": {"result": 42}},
_meta={"internal": "metadata"},
)
@mcp.tool()
def empty_result_tool() -> CallToolResult:
"""For empty results, return CallToolResult with empty content."""
return CallToolResult(content=[])
```
_Full example: [examples/snippets/servers/direct_call_tool_result.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/direct_call_tool_result.py)_
<!-- /snippet-source -->
**Important:** `CallToolResult` must always be returned (no `Optional` or `Union`). For empty results, use `CallToolResult(content=[])`. For optional simple types, use `str | None` without `CallToolResult`.
<!-- snippet-source examples/snippets/servers/structured_output.py -->
```python
"""Example showing structured output with tools."""
from typing import TypedDict
from pydantic import BaseModel, Field
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("Structured Output Example")
# Using Pydantic models for rich structured data
class WeatherData(BaseModel):
"""Weather information structure."""
temperature: float = Field(description="Temperature in Celsius")
humidity: float = Field(description="Humidity percentage")
condition: str
wind_speed: float
@mcp.tool()
def get_weather(city: str) -> WeatherData:
"""Get weather for a city - returns structured data."""
# Simulated weather data
return WeatherData(
temperature=22.5,
humidity=45.0,
condition="sunny",
wind_speed=5.2,
)
# Using TypedDict for simpler structures
class LocationInfo(TypedDict):
latitude: float
longitude: float
name: str
@mcp.tool()
def get_location(address: str) -> LocationInfo:
"""Get location coordinates"""
return LocationInfo(latitude=51.5074, longitude=-0.1278, name="London, UK")
# Using dict[str, Any] for flexible schemas
@mcp.tool()
def get_statistics(data_type: str) -> dict[str, float]:
"""Get various statistics"""
return {"mean": 42.5, "median": 40.0, "std_dev": 5.2}
# Ordinary classes with type hints work for structured output
class UserProfile:
name: str
age: int
email: str | None = None
def __init__(self, name: str, age: int, email: str | None = None):
self.name = name
self.age = age
self.email = email
@mcp.tool()
def get_user(user_id: str) -> UserProfile:
"""Get user profile - returns structured data"""
return UserProfile(name="Alice", age=30, email="alice@example.com")
# Classes WITHOUT type hints cannot be used for structured output
class UntypedConfig:
def __init__(self, setting1, setting2): # type: ignore[reportMissingParameterType]
self.setting1 = setting1
self.setting2 = setting2
@mcp.tool()
def get_config() -> UntypedConfig:
"""This returns unstructured output - no schema generated"""
return UntypedConfig("value1", "value2")
# Lists and other types are wrapped automatically
@mcp.tool()
def list_cities() -> list[str]:
"""Get a list of cities"""
return ["London", "Paris", "Tokyo"]
# Returns: {"result": ["London", "Paris", "Tokyo"]}
@mcp.tool()
def get_temperature(city: str) -> float:
"""Get temperature as a simple float"""
return 22.5
# Returns: {"result": 22.5}
```
_Full example: [examples/snippets/servers/structured_output.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/structured_output.py)_
<!-- /snippet-source -->
### Prompts
Prompts are reusable templates that help LLMs interact with your server effectively:
<!-- snippet-source examples/snippets/servers/basic_prompt.py -->
```python
from mcp.server.fastmcp import FastMCP
from mcp.server.fastmcp.prompts import base
mcp = FastMCP(name="Prompt Example")
@mcp.prompt(title="Code Review")
def review_code(code: str) -> str:
return f"Please review this code:\n\n{code}"
@mcp.prompt(title="Debug Assistant")
def debug_error(error: str) -> list[base.Message]:
return [
base.UserMessage("I'm seeing this error:"),
base.UserMessage(error),
base.AssistantMessage("I'll help debug that. What have you tried so far?"),
]
```
_Full example: [examples/snippets/servers/basic_prompt.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/basic_prompt.py)_
<!-- /snippet-source -->
### Icons
MCP servers can provide icons for UI display. Icons can be added to the server implementation, tools, resources, and prompts:
```python
from mcp.server.fastmcp import FastMCP, Icon
# Create an icon from a file path or URL
icon = Icon(
src="icon.png",
mimeType="image/png",
sizes="64x64"
)
# Add icons to server
mcp = FastMCP(
"My Server",
website_url="https://example.com",
icons=[icon]
)
# Add icons to tools, resources, and prompts
@mcp.tool(icons=[icon])
def my_tool():
"""Tool with an icon."""
return "result"
@mcp.resource("demo://resource", icons=[icon])
def my_resource():
"""Resource with an icon."""
return "content"
```
_Full example: [examples/fastmcp/icons_demo.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/fastmcp/icons_demo.py)_
### Images
FastMCP provides an `Image` class that automatically handles image data:
<!-- snippet-source examples/snippets/servers/images.py -->
```python
"""Example showing image handling with FastMCP."""
from PIL import Image as PILImage
from mcp.server.fastmcp import FastMCP, Image
mcp = FastMCP("Image Example")
@mcp.tool()
def create_thumbnail(image_path: str) -> Image:
"""Create a thumbnail from an image"""
img = PILImage.open(image_path)
img.thumbnail((100, 100))
return Image(data=img.tobytes(), format="png")
```
_Full example: [examples/snippets/servers/images.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/images.py)_
<!-- /snippet-source -->
### Context
The Context object is automatically injected into tool and resource functions that request it via type hints. It provides access to MCP capabilities like logging, progress reporting, resource reading, user interaction, and request metadata.
#### Getting Context in Functions
To use context in a tool or resource function, add a parameter with the `Context` type annotation:
```python
from mcp.server.fastmcp import Context, FastMCP
mcp = FastMCP(name="Context Example")
@mcp.tool()
async def my_tool(x: int, ctx: Context) -> str:
"""Tool that uses context capabilities."""
# The context parameter can have any name as long as it's type-annotated
return await process_with_context(x, ctx)
```
#### Context Properties and Methods
The Context object provides the following capabilities:
- `ctx.request_id` - Unique ID for the current request
- `ctx.client_id` - Client ID if available
- `ctx.fastmcp` - Access to the FastMCP server instance (see [FastMCP Properties](#fastmcp-properties))
- `ctx.session` - Access to the underlying session for advanced communication (see [Session Properties and Methods](#session-properties-and-methods))
- `ctx.request_context` - Access to request-specific data and lifespan resources (see [Request Context Properties](#request-context-properties))
- `await ctx.debug(message)` - Send debug log message
- `await ctx.info(message)` - Send info log message
- `await ctx.warning(message)` - Send warning log message
- `await ctx.error(message)` - Send error log message
- `await ctx.log(level, message, logger_name=None)` - Send log with custom level
- `await ctx.report_progress(progress, total=None, message=None)` - Report operation progress
- `await ctx.read_resource(uri)` - Read a resource by URI
- `await ctx.elicit(message, schema)` - Request additional information from user with validation
<!-- snippet-source examples/snippets/servers/tool_progress.py -->
```python
from mcp.server.fastmcp import Context, FastMCP
from mcp.server.session import ServerSession
mcp = FastMCP(name="Progress Example")
@mcp.tool()
async def long_running_task(task_name: str, ctx: Context[ServerSession, None], steps: int = 5) -> str:
"""Execute a task with progress updates."""
await ctx.info(f"Starting: {task_name}")
for i in range(steps):
progress = (i + 1) / steps
await ctx.report_progress(
progress=progress,
total=1.0,
message=f"Step {i + 1}/{steps}",
)
await ctx.debug(f"Completed step {i + 1}")
return f"Task '{task_name}' completed"
```
_Full example: [examples/snippets/servers/tool_progress.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/tool_progress.py)_
<!-- /snippet-source -->
### Completions
MCP supports providing completion suggestions for prompt arguments and resource template parameters. With the context parameter, servers can provide completions based on previously resolved values:
Client usage:
<!-- snippet-source examples/snippets/clients/completion_client.py -->
```python
"""
cd to the `examples/snippets` directory and run:
uv run completion-client
"""
import asyncio
import os
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
from mcp.types import PromptReference, ResourceTemplateReference
# Create server parameters for stdio connection
server_params = StdioServerParameters(
command="uv", # Using uv to run the server
args=["run", "server", "completion", "stdio"], # Server with completion support
env={"UV_INDEX": os.environ.get("UV_INDEX", "")},
)
async def run():
"""Run the completion client example."""
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
# Initialize the connection
await session.initialize()
# List available resource templates
templates = await session.list_resource_templates()
print("Available resource templates:")
for template in templates.resourceTemplates:
print(f" - {template.uriTemplate}")
# List available prompts
prompts = await session.list_prompts()
print("\nAvailable prompts:")
for prompt in prompts.prompts:
print(f" - {prompt.name}")
# Complete resource template arguments
if templates.resourceTemplates:
template = templates.resourceTemplates[0]
print(f"\nCompleting arguments for resource template: {template.uriTemplate}")
# Complete without context
result = await session.complete(
ref=ResourceTemplateReference(type="ref/resource", uri=template.uriTemplate),
argument={"name": "owner", "value": "model"},
)
print(f"Completions for 'owner' starting with 'model': {result.completion.values}")
# Complete with context - repo suggestions based on owner
result = await session.complete(
ref=ResourceTemplateReference(type="ref/resource", uri=template.uriTemplate),
argument={"name": "repo", "value": ""},
context_arguments={"owner": "modelcontextprotocol"},
)
print(f"Completions for 'repo' with owner='modelcontextprotocol': {result.completion.values}")
# Complete prompt arguments
if prompts.prompts:
prompt_name = prompts.prompts[0].name
print(f"\nCompleting arguments for prompt: {prompt_name}")
result = await session.complete(
ref=PromptReference(type="ref/prompt", name=prompt_name),
argument={"name": "style", "value": ""},
)
print(f"Completions for 'style' argument: {result.completion.values}")
def main():
"""Entry point for the completion client."""
asyncio.run(run())
if __name__ == "__main__":
main()
```
_Full example: [examples/snippets/clients/completion_client.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/clients/completion_client.py)_
<!-- /snippet-source -->
### Elicitation
Request additional information from users. This example shows an Elicitation during a Tool Call:
<!-- snippet-source examples/snippets/servers/elicitation.py -->
```python
"""Elicitation examples demonstrating form and URL mode elicitation.
Form mode elicitation collects structured, non-sensitive data through a schema.
URL mode elicitation directs users to external URLs for sensitive operations
like OAuth flows, credential collection, or payment processing.
"""
import uuid
from pydantic import BaseModel, Field
from mcp.server.fastmcp import Context, FastMCP
from mcp.server.session import ServerSession
from mcp.shared.exceptions import UrlElicitationRequiredError
from mcp.types import ElicitRequestURLParams
mcp = FastMCP(name="Elicitation Example")
class BookingPreferences(BaseModel):
"""Schema for collecting user preferences."""
checkAlternative: bool = Field(description="Would you like to check another date?")
alternativeDate: str = Field(
default="2024-12-26",
description="Alternative date (YYYY-MM-DD)",
)
@mcp.tool()
async def book_table(date: str, time: str, party_size: int, ctx: Context[ServerSession, None]) -> str:
"""Book a table with date availability check.
This demonstrates form mode elicitation for collecting non-sensitive user input.
"""
# Check if date is available
if date == "2024-12-25":
# Date unavailable - ask user for alternative
result = await ctx.elicit(
message=(f"No tables available for {party_size} on {date}. Would you like to try another date?"),
schema=BookingPreferences,
)
if result.action == "accept" and result.data:
if result.data.checkAlternative:
return f"[SUCCESS] Booked for {result.data.alternativeDate}"
return "[CANCELLED] No booking made"
return "[CANCELLED] Booking cancelled"
# Date available
return f"[SUCCESS] Booked for {date} at {time}"
@mcp.tool()
async def secure_payment(amount: float, ctx: Context[ServerSession, None]) -> str:
"""Process a secure payment requiring URL confirmation.
This demonstrates URL mode elicitation using ctx.elicit_url() for
operations that require out-of-band user interaction.
"""
elicitation_id = str(uuid.uuid4())
result = await ctx.elicit_url(
message=f"Please confirm payment of ${amount:.2f}",
url=f"https://payments.example.com/confirm?amount={amount}&id={elicitation_id}",
elicitation_id=elicitation_id,
)
if result.action == "accept":
# In a real app, the payment confirmation would happen out-of-band
# and you'd verify the payment status from your backend
return f"Payment of ${amount:.2f} initiated - check your browser to complete"
elif result.action == "decline":
return "Payment declined by user"
return "Payment cancelled"
@mcp.tool()
async def connect_service(service_name: str, ctx: Context[ServerSession, None]) -> str:
"""Connect to a third-party service requiring OAuth authorization.
This demonstrates the "throw error" pattern using UrlElicitationRequiredError.
Use this pattern when the tool cannot proceed without user authorization.
"""
elicitation_id = str(uuid.uuid4())
# Raise UrlElicitationRequiredError to signal that the client must complete
# a URL elicitation before this request can be processed.
# The MCP framework will convert this to a -32042 error response.
raise UrlElicitationRequiredError(
[
ElicitRequestURLParams(
mode="url",
message=f"Authorization required to connect to {service_name}",
url=f"https://{service_name}.example.com/oauth/authorize?elicit={elicitation_id}",
elicitationId=elicitation_id,
)
]
)
```
_Full example: [examples/snippets/servers/elicitation.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/elicitation.py)_
<!-- /snippet-source -->
Elicitation schemas support default values for all field types. Default values are automatically included in the JSON schema sent to clients, allowing them to pre-populate forms.
The `elicit()` method returns an `ElicitationResult` with:
- `action`: "accept", "decline", or "cancel"
- `data`: The validated response (only when accepted)
- `validation_error`: Any validation error message
### Sampling
Tools can interact with LLMs through sampling (generating text):
<!-- snippet-source examples/snippets/servers/sampling.py -->
```python
from mcp.server.fastmcp import Context, FastMCP
from mcp.server.session import ServerSession
from mcp.types import SamplingMessage, TextContent
mcp = FastMCP(name="Sampling Example")
@mcp.tool()
async def generate_poem(topic: str, ctx: Context[ServerSession, None]) -> str:
"""Generate a poem using LLM sampling."""
prompt = f"Write a short poem about {topic}"
result = await ctx.session.create_message(
messages=[
SamplingMessage(
role="user",
content=TextContent(type="text", text=prompt),
)
],
max_tokens=100,
)
# Since we're not passing tools param, result.content is single content
if result.content.type == "text":
return result.content.text
return str(result.content)
```
_Full example: [examples/snippets/servers/sampling.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/sampling.py)_
<!-- /snippet-source -->
### Logging and Notifications
Tools can send logs and notifications through the context:
<!-- snippet-source examples/snippets/servers/notifications.py -->
```python
from mcp.server.fastmcp import Context, FastMCP
from mcp.server.session import ServerSession
mcp = FastMCP(name="Notifications Example")
@mcp.tool()
async def process_data(data: str, ctx: Context[ServerSession, None]) -> str:
"""Process data with logging."""
# Different log levels
await ctx.debug(f"Debug: Processing '{data}'")
await ctx.info("Info: Starting processing")
await ctx.warning("Warning: This is experimental")
await ctx.error("Error: (This is just a demo)")
# Notify about resource changes
await ctx.session.send_resource_list_changed()
return f"Processed: {data}"
```
_Full example: [examples/snippets/servers/notifications.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/notifications.py)_
<!-- /snippet-source -->
### Authentication
Authentication can be used by servers that want to expose tools accessing protected resources.
`mcp.server.auth` implements OAuth 2.1 resource server functionality, where MCP servers act as Resource Servers (RS) that validate tokens issued by separate Authorization Servers (AS). This follows the [MCP authorization specification](https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization) and implements RFC 9728 (Protected Resource Metadata) for AS discovery.
MCP servers can use authentication by providing an implementation of the `TokenVerifier` protocol:
<!-- snippet-source examples/snippets/servers/oauth_server.py -->
```python
"""
Run from the repository root:
uv run examples/snippets/servers/oauth_server.py
"""
from pydantic import AnyHttpUrl
from mcp.server.auth.provider import AccessToken, TokenVerifier
from mcp.server.auth.settings import AuthSettings
from mcp.server.fastmcp import FastMCP
class SimpleTokenVerifier(TokenVerifier):
"""Simple token verifier for demonstration."""
async def verify_token(self, token: str) -> AccessToken | None:
pass # This is where you would implement actual token validation
# Create FastMCP instance as a Resource Server
mcp = FastMCP(
"Weather Service",
json_response=True,
# Token verifier for authentication
token_verifier=SimpleTokenVerifier(),
# Auth settings for RFC 9728 Protected Resource Metadata
auth=AuthSettings(
issuer_url=AnyHttpUrl("https://auth.example.com"), # Authorization Server URL
resource_server_url=AnyHttpUrl("http://localhost:3001"), # This server's URL
required_scopes=["user"],
),
)
@mcp.tool()
async def get_weather(city: str = "London") -> dict[str, str]:
"""Get weather data for a city"""
return {
"city": city,
"temperature": "22",
"condition": "Partly cloudy",
"humidity": "65%",
}
if __name__ == "__main__":
mcp.run(transport="streamable-http")
```
_Full example: [examples/snippets/servers/oauth_server.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/oauth_server.py)_
<!-- /snippet-source -->
For a complete example with separate Authorization Server and Resource Server implementations, see [`examples/servers/simple-auth/`](examples/servers/simple-auth/).
**Architecture:**
- **Authorization Server (AS)**: Handles OAuth flows, user authentication, and token issuance
- **Resource Server (RS)**: Your MCP server that validates tokens and serves protected resources
- **Client**: Discovers AS through RFC 9728, obtains tokens, and uses them with the MCP server
See [TokenVerifier](src/mcp/server/auth/provider.py) for more details on implementing token validation.
### FastMCP Properties
The FastMCP server instance accessible via `ctx.fastmcp` provides access to server configuration and metadata:
- `ctx.fastmcp.name` - The server's name as defined during initialization
- `ctx.fastmcp.instructions` - Server instructions/description provided to clients
- `ctx.fastmcp.website_url` - Optional website URL for the server
- `ctx.fastmcp.icons` - Optional list of icons for UI display
- `ctx.fastmcp.settings` - Complete server configuration object containing:
- `debug` - Debug mode flag
- `log_level` - Current logging level
- `host` and `port` - Server network configuration
- `mount_path`, `sse_path`, `streamable_http_path` - Transport paths
- `stateless_http` - Whether the server operates in stateless mode
- And other configuration options
```python
@mcp.tool()
def server_info(ctx: Context) -> dict:
"""Get information about the current server."""
return {
"name": ctx.fastmcp.name,
"instructions": ctx.fastmcp.instructions,
"debug_mode": ctx.fastmcp.settings.debug,
"log_level": ctx.fastmcp.settings.log_level,
"host": ctx.fastmcp.settings.host,
"port": ctx.fastmcp.settings.port,
}
```
### Session Properties and Methods
The session object accessible via `ctx.session` provides advanced control over client communication:
- `ctx.session.client_params` - Client initialization parameters and declared capabilities
- `await ctx.session.send_log_message(level, data, logger)` - Send log messages with full control
- `await ctx.session.create_message(messages, max_tokens)` - Request LLM sampling/completion
- `await ctx.session.send_progress_notification(token, progress, total, message)` - Direct progress updates
- `await ctx.session.send_resource_updated(uri)` - Notify clients that a specific resource changed
- `await ctx.session.send_resource_list_changed()` - Notify clients that the resource list changed
- `await ctx.session.send_tool_list_changed()` - Notify clients that the tool list changed
- `await ctx.session.send_prompt_list_changed()` - Notify clients that the prompt list changed
```python
@mcp.tool()
async def notify_data_update(resource_uri: str, ctx: Context) -> str:
"""Update data and notify clients of the change."""
# Perform data update logic here
# Notify clients that this specific resource changed
await ctx.session.send_resource_updated(AnyUrl(resource_uri))
# If this affects the overall resource list, notify about that too
await ctx.session.send_resource_list_changed()
return f"Updated {resource_uri} and notified clients"
```
### Request Context Properties
The request context accessible via `ctx.request_context` contains request-specific information and resources:
- `ctx.request_context.lifespan_context` - Access to resources initialized during server startup
- Database connections, configuration objects, shared services
- Type-safe access to resources defined in your server's lifespan function
- `ctx.request_context.meta` - Request metadata from the client including:
- `progressToken` - Token for progress notifications
- Other client-provided metadata
- `ctx.request_context.request` - The original MCP request object for advanced processing
- `ctx.request_context.request_id` - Unique identifier for this request
```python
# Example with typed lifespan context
@dataclass
class AppContext:
db: Database
config: AppConfig
@mcp.tool()
def query_with_config(query: str, ctx: Context) -> str:
"""Execute a query using shared database and configuration."""
# Access typed lifespan context
app_ctx: AppContext = ctx.request_context.lifespan_context
# Use shared resources
connection = app_ctx.db
settings = app_ctx.config
# Execute query with configuration
result = connection.execute(query, timeout=settings.query_timeout)
return str(result)
```
_Full lifespan example: [examples/snippets/servers/lifespan_example.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/lifespan_example.py)_
## Running Your Server
### Development Mode
The fastest way to test and debug your server is with the MCP Inspector:
```bash
uv run mcp dev server.py
# Add dependencies
uv run mcp dev server.py --with pandas --with numpy
# Mount local code
uv run mcp dev server.py --with-editable .
```
### Claude Desktop Integration
Once your server is ready, install it in Claude Desktop:
```bash
uv run mcp install server.py
# Custom name
uv run mcp install server.py --name "My Analytics Server"
# Environment variables
uv run mcp install server.py -v API_KEY=abc123 -v DB_URL=postgres://...
uv run mcp install server.py -f .env
```
### Direct Execution
For advanced scenarios like custom deployments:
<!-- snippet-source examples/snippets/servers/direct_execution.py -->
```python
"""Example showing direct execution of an MCP server.
This is the simplest way to run an MCP server directly.
cd to the `examples/snippets` directory and run:
uv run direct-execution-server
or
python servers/direct_execution.py
"""
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("My App")
@mcp.tool()
def hello(name: str = "World") -> str:
"""Say hello to someone."""
return f"Hello, {name}!"
def main():
"""Entry point for the direct execution server."""
mcp.run()
if __name__ == "__main__":
main()
```
_Full example: [examples/snippets/servers/direct_execution.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/direct_execution.py)_
<!-- /snippet-source -->
Run it with:
```bash
python servers/direct_execution.py
# or
uv run mcp run servers/direct_execution.py
```
Note that `uv run mcp run` or `uv run mcp dev` only supports server using FastMCP and not the low-level server variant.
### Streamable HTTP Transport
> **Note**: Streamable HTTP transport is the recommended transport for production deployments. Use `stateless_http=True` and `json_response=True` for optimal scalability.
<!-- snippet-source examples/snippets/servers/streamable_config.py -->
```python
"""
Run from the repository root:
uv run examples/snippets/servers/streamable_config.py
"""
from mcp.server.fastmcp import FastMCP
# Stateless server with JSON responses (recommended)
mcp = FastMCP("StatelessServer", stateless_http=True, json_response=True)
# Other configuration options:
# Stateless server with SSE streaming responses
# mcp = FastMCP("StatelessServer", stateless_http=True)
# Stateful server with session persistence
# mcp = FastMCP("StatefulServer")
# Add a simple tool to demonstrate the server
@mcp.tool()
def greet(name: str = "World") -> str:
"""Greet someone by name."""
return f"Hello, {name}!"
# Run server with streamable_http transport
if __name__ == "__main__":
mcp.run(transport="streamable-http")
```
_Full example: [examples/snippets/servers/streamable_config.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/streamable_config.py)_
<!-- /snippet-source -->
You can mount multiple FastMCP servers in a Starlette application:
<!-- snippet-source examples/snippets/servers/streamable_starlette_mount.py -->
```python
"""
Run from the repository root:
uvicorn examples.snippets.servers.streamable_starlette_mount:app --reload
"""
import contextlib
from starlette.applications import Starlette
from starlette.routing import Mount
from mcp.server.fastmcp import FastMCP
# Create the Echo server
echo_mcp = FastMCP(name="EchoServer", stateless_http=True, json_response=True)
@echo_mcp.tool()
def echo(message: str) -> str:
"""A simple echo tool"""
return f"Echo: {message}"
# Create the Math server
math_mcp = FastMCP(name="MathServer", stateless_http=True, json_response=True)
@math_mcp.tool()
def add_two(n: int) -> int:
"""Tool to add two to the input"""
return n + 2
# Create a combined lifespan to manage both session managers
@contextlib.asynccontextmanager
async def lifespan(app: Starlette):
async with contextlib.AsyncExitStack() as stack:
await stack.enter_async_context(echo_mcp.session_manager.run())
await stack.enter_async_context(math_mcp.session_manager.run())
yield
# Create the Starlette app and mount the MCP servers
app = Starlette(
routes=[
Mount("/echo", echo_mcp.streamable_http_app()),
Mount("/math", math_mcp.streamable_http_app()),
],
lifespan=lifespan,
)
# Note: Clients connect to http://localhost:8000/echo/mcp and http://localhost:8000/math/mcp
# To mount at the root of each path (e.g., /echo instead of /echo/mcp):
# echo_mcp.settings.streamable_http_path = "/"
# math_mcp.settings.streamable_http_path = "/"
```
_Full example: [examples/snippets/servers/streamable_starlette_mount.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/streamable_starlette_mount.py)_
<!-- /snippet-source -->
For low level server with Streamable HTTP implementations, see:
- Stateful server: [`examples/servers/simple-streamablehttp/`](examples/servers/simple-streamablehttp/)
- Stateless server: [`examples/servers/simple-streamablehttp-stateless/`](examples/servers/simple-streamablehttp-stateless/)
The streamable HTTP transport supports:
- Stateful and stateless operation modes
- Resumability with event stores
- JSON or SSE response formats
- Better scalability for multi-node deployments
#### CORS Configuration for Browser-Based Clients
If you'd like your server to be accessible by browser-based MCP clients, you'll need to configure CORS headers. The `Mcp-Session-Id` header must be exposed for browser clients to access it:
```python
from starlette.applications import Starlette
from starlette.middleware.cors import CORSMiddleware
# Create your Starlette app first
starlette_app = Starlette(routes=[...])
# Then wrap it with CORS middleware
starlette_app = CORSMiddleware(
starlette_app,
allow_origins=["*"], # Configure appropriately for production
allow_methods=["GET", "POST", "DELETE"], # MCP streamable HTTP methods
expose_headers=["Mcp-Session-Id"],
)
```
This configuration is necessary because:
- The MCP streamable HTTP transport uses the `Mcp-Session-Id` header for session management
- Browsers restrict access to response headers unless explicitly exposed via CORS
- Without this configuration, browser-based clients won't be able to read the session ID from initialization responses
### Mounting to an Existing ASGI Server
By default, SSE servers are mounted at `/sse` and Streamable HTTP servers are mounted at `/mcp`. You can customize these paths using the methods described below.
For more information on mounting applications in Starlette, see the [Starlette documentation](https://www.starlette.io/routing/#submounting-routes).
#### StreamableHTTP servers
You can mount the StreamableHTTP server to an existing ASGI server using the `streamable_http_app` method. This allows you to integrate the StreamableHTTP server with other ASGI applications.
##### Basic mounting
<!-- snippet-source examples/snippets/servers/streamable_http_basic_mounting.py -->
```python
"""
Basic example showing how to mount StreamableHTTP server in Starlette.
Run from the repository root:
uvicorn examples.snippets.servers.streamable_http_basic_mounting:app --reload
"""
import contextlib
from starlette.applications import Starlette
from starlette.routing import Mount
from mcp.server.fastmcp import FastMCP
# Create MCP server
mcp = FastMCP("My App", json_response=True)
@mcp.tool()
def hello() -> str:
"""A simple hello tool"""
return "Hello from MCP!"
# Create a lifespan context manager to run the session manager
@contextlib.asynccontextmanager
async def lifespan(app: Starlette):
async with mcp.session_manager.run():
yield
# Mount the StreamableHTTP server to the existing ASGI server
app = Starlette(
routes=[
Mount("/", app=mcp.streamable_http_app()),
],
lifespan=lifespan,
)
```
_Full example: [examples/snippets/servers/streamable_http_basic_mounting.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/streamable_http_basic_mounting.py)_
<!-- /snippet-source -->
##### Host-based routing
<!-- snippet-source examples/snippets/servers/streamable_http_host_mounting.py -->
```python
"""
Example showing how to mount StreamableHTTP server using Host-based routing.
Run from the repository root:
uvicorn examples.snippets.servers.streamable_http_host_mounting:app --reload
"""
import contextlib
from starlette.applications import Starlette
from starlette.routing import Host
from mcp.server.fastmcp import FastMCP
# Create MCP server
mcp = FastMCP("MCP Host App", json_response=True)
@mcp.tool()
def domain_info() -> str:
"""Get domain-specific information"""
return "This is served from mcp.acme.corp"
# Create a lifespan context manager to run the session manager
@contextlib.asynccontextmanager
async def lifespan(app: Starlette):
async with mcp.session_manager.run():
yield
# Mount using Host-based routing
app = Starlette(
routes=[
Host("mcp.acme.corp", app=mcp.streamable_http_app()),
],
lifespan=lifespan,
)
```
_Full example: [examples/snippets/servers/streamable_http_host_mounting.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/streamable_http_host_mounting.py)_
<!-- /snippet-source -->
##### Multiple servers with path configuration
<!-- snippet-source examples/snippets/servers/streamable_http_multiple_servers.py -->
```python
"""
Example showing how to mount multiple StreamableHTTP servers with path configuration.
Run from the repository root:
uvicorn examples.snippets.servers.streamable_http_multiple_servers:app --reload
"""
import contextlib
from starlette.applications import Starlette
from starlette.routing import Mount
from mcp.server.fastmcp import FastMCP
# Create multiple MCP servers
api_mcp = FastMCP("API Server", json_response=True)
chat_mcp = FastMCP("Chat Server", json_response=True)
@api_mcp.tool()
def api_status() -> str:
"""Get API status"""
return "API is running"
@chat_mcp.tool()
def send_message(message: str) -> str:
"""Send a chat message"""
return f"Message sent: {message}"
# Configure servers to mount at the root of each path
# This means endpoints will be at /api and /chat instead of /api/mcp and /chat/mcp
api_mcp.settings.streamable_http_path = "/"
chat_mcp.settings.streamable_http_path = "/"
# Create a combined lifespan to manage both session managers
@contextlib.asynccontextmanager
async def lifespan(app: Starlette):
async with contextlib.AsyncExitStack() as stack:
await stack.enter_async_context(api_mcp.session_manager.run())
await stack.enter_async_context(chat_mcp.session_manager.run())
yield
# Mount the servers
app = Starlette(
routes=[
Mount("/api", app=api_mcp.streamable_http_app()),
Mount("/chat", app=chat_mcp.streamable_http_app()),
],
lifespan=lifespan,
)
```
_Full example: [examples/snippets/servers/streamable_http_multiple_servers.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/streamable_http_multiple_servers.py)_
<!-- /snippet-source -->
##### Path configuration at initialization
<!-- snippet-source examples/snippets/servers/streamable_http_path_config.py -->
```python
"""
Example showing path configuration during FastMCP initialization.
Run from the repository root:
uvicorn examples.snippets.servers.streamable_http_path_config:app --reload
"""
from starlette.applications import Starlette
from starlette.routing import Mount
from mcp.server.fastmcp import FastMCP
# Configure streamable_http_path during initialization
# This server will mount at the root of wherever it's mounted
mcp_at_root = FastMCP(
"My Server",
json_response=True,
streamable_http_path="/",
)
@mcp_at_root.tool()
def process_data(data: str) -> str:
"""Process some data"""
return f"Processed: {data}"
# Mount at /process - endpoints will be at /process instead of /process/mcp
app = Starlette(
routes=[
Mount("/process", app=mcp_at_root.streamable_http_app()),
]
)
```
_Full example: [examples/snippets/servers/streamable_http_path_config.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/streamable_http_path_config.py)_
<!-- /snippet-source -->
#### SSE servers
> **Note**: SSE transport is being superseded by [Streamable HTTP transport](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http).
You can mount the SSE server to an existing ASGI server using the `sse_app` method. This allows you to integrate the SSE server with other ASGI applications.
```python
from starlette.applications import Starlette
from starlette.routing import Mount, Host
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("My App")
# Mount the SSE server to the existing ASGI server
app = Starlette(
routes=[
Mount('/', app=mcp.sse_app()),
]
)
# or dynamically mount as host
app.router.routes.append(Host('mcp.acme.corp', app=mcp.sse_app()))
```
When mounting multiple MCP servers under different paths, you can configure the mount path in several ways:
```python
from starlette.applications import Starlette
from starlette.routing import Mount
from mcp.server.fastmcp import FastMCP
# Create multiple MCP servers
github_mcp = FastMCP("GitHub API")
browser_mcp = FastMCP("Browser")
curl_mcp = FastMCP("Curl")
search_mcp = FastMCP("Search")
# Method 1: Configure mount paths via settings (recommended for persistent configuration)
github_mcp.settings.mount_path = "/github"
browser_mcp.settings.mount_path = "/browser"
# Method 2: Pass mount path directly to sse_app (preferred for ad-hoc mounting)
# This approach doesn't modify the server's settings permanently
# Create Starlette app with multiple mounted servers
app = Starlette(
routes=[
# Using settings-based configuration
Mount("/github", app=github_mcp.sse_app()),
Mount("/browser", app=browser_mcp.sse_app()),
# Using direct mount path parameter
Mount("/curl", app=curl_mcp.sse_app("/curl")),
Mount("/search", app=search_mcp.sse_app("/search")),
]
)
# Method 3: For direct execution, you can also pass the mount path to run()
if __name__ == "__main__":
search_mcp.run(transport="sse", mount_path="/search")
```
For more information on mounting applications in Starlette, see the [Starlette documentation](https://www.starlette.io/routing/#submounting-routes).
## Advanced Usage
### Low-Level Server
For more control, you can use the low-level server implementation directly. This gives you full access to the protocol and allows you to customize every aspect of your server, including lifecycle management through the lifespan API:
<!-- snippet-source examples/snippets/servers/lowlevel/lifespan.py -->
```python
"""
Run from the repository root:
uv run examples/snippets/servers/lowlevel/lifespan.py
"""
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from typing import Any
import mcp.server.stdio
import mcp.types as types
from mcp.server.lowlevel import NotificationOptions, Server
from mcp.server.models import InitializationOptions
# Mock database class for example
class Database:
"""Mock database class for example."""
@classmethod
async def connect(cls) -> "Database":
"""Connect to database."""
print("Database connected")
return cls()
async def disconnect(self) -> None:
"""Disconnect from database."""
print("Database disconnected")
async def query(self, query_str: str) -> list[dict[str, str]]:
"""Execute a query."""
# Simulate database query
return [{"id": "1", "name": "Example", "query": query_str}]
@asynccontextmanager
async def server_lifespan(_server: Server) -> AsyncIterator[dict[str, Any]]:
"""Manage server startup and shutdown lifecycle."""
# Initialize resources on startup
db = await Database.connect()
try:
yield {"db": db}
finally:
# Clean up on shutdown
await db.disconnect()
# Pass lifespan to server
server = Server("example-server", lifespan=server_lifespan)
@server.list_tools()
async def handle_list_tools() -> list[types.Tool]:
"""List available tools."""
return [
types.Tool(
name="query_db",
description="Query the database",
inputSchema={
"type": "object",
"properties": {"query": {"type": "string", "description": "SQL query to execute"}},
"required": ["query"],
},
)
]
@server.call_tool()
async def query_db(name: str, arguments: dict[str, Any]) -> list[types.TextContent]:
"""Handle database query tool call."""
if name != "query_db":
raise ValueError(f"Unknown tool: {name}")
# Access lifespan context
ctx = server.request_context
db = ctx.lifespan_context["db"]
# Execute query
results = await db.query(arguments["query"])
return [types.TextContent(type="text", text=f"Query results: {results}")]
async def run():
"""Run the server with lifespan management."""
async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
await server.run(
read_stream,
write_stream,
InitializationOptions(
server_name="example-server",
server_version="0.1.0",
capabilities=server.get_capabilities(
notification_options=NotificationOptions(),
experimental_capabilities={},
),
),
)
if __name__ == "__main__":
import asyncio
asyncio.run(run())
```
_Full example: [examples/snippets/servers/lowlevel/lifespan.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/lowlevel/lifespan.py)_
<!-- /snippet-source -->
The lifespan API provides:
- A way to initialize resources when the server starts and clean them up when it stops
- Access to initialized resources through the request context in handlers
- Type-safe context passing between lifespan and request handlers
<!-- snippet-source examples/snippets/servers/lowlevel/basic.py -->
```python
"""
Run from the repository root:
uv run examples/snippets/servers/lowlevel/basic.py
"""
import asyncio
import mcp.server.stdio
import mcp.types as types
from mcp.server.lowlevel import NotificationOptions, Server
from mcp.server.models import InitializationOptions
# Create a server instance
server = Server("example-server")
@server.list_prompts()
async def handle_list_prompts() -> list[types.Prompt]:
"""List available prompts."""
return [
types.Prompt(
name="example-prompt",
description="An example prompt template",
arguments=[types.PromptArgument(name="arg1", description="Example argument", required=True)],
)
]
@server.get_prompt()
async def handle_get_prompt(name: str, arguments: dict[str, str] | None) -> types.GetPromptResult:
"""Get a specific prompt by name."""
if name != "example-prompt":
raise ValueError(f"Unknown prompt: {name}")
arg1_value = (arguments or {}).get("arg1", "default")
return types.GetPromptResult(
description="Example prompt",
messages=[
types.PromptMessage(
role="user",
content=types.TextContent(type="text", text=f"Example prompt text with argument: {arg1_value}"),
)
],
)
async def run():
"""Run the basic low-level server."""
async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
await server.run(
read_stream,
write_stream,
InitializationOptions(
server_name="example",
server_version="0.1.0",
capabilities=server.get_capabilities(
notification_options=NotificationOptions(),
experimental_capabilities={},
),
),
)
if __name__ == "__main__":
asyncio.run(run())
```
_Full example: [examples/snippets/servers/lowlevel/basic.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/lowlevel/basic.py)_
<!-- /snippet-source -->
Caution: The `uv run mcp run` and `uv run mcp dev` tool doesn't support low-level server.
#### Structured Output Support
The low-level server supports structured output for tools, allowing you to return both human-readable content and machine-readable structured data. Tools can define an `outputSchema` to validate their structured output:
<!-- snippet-source examples/snippets/servers/lowlevel/structured_output.py -->
```python
"""
Run from the repository root:
uv run examples/snippets/servers/lowlevel/structured_output.py
"""
import asyncio
from typing import Any
import mcp.server.stdio
import mcp.types as types
from mcp.server.lowlevel import NotificationOptions, Server
from mcp.server.models import InitializationOptions
server = Server("example-server")
@server.list_tools()
async def list_tools() -> list[types.Tool]:
"""List available tools with structured output schemas."""
return [
types.Tool(
name="get_weather",
description="Get current weather for a city",
inputSchema={
"type": "object",
"properties": {"city": {"type": "string", "description": "City name"}},
"required": ["city"],
},
outputSchema={
"type": "object",
"properties": {
"temperature": {"type": "number", "description": "Temperature in Celsius"},
"condition": {"type": "string", "description": "Weather condition"},
"humidity": {"type": "number", "description": "Humidity percentage"},
"city": {"type": "string", "description": "City name"},
},
"required": ["temperature", "condition", "humidity", "city"],
},
)
]
@server.call_tool()
async def call_tool(name: str, arguments: dict[str, Any]) -> dict[str, Any]:
"""Handle tool calls with structured output."""
if name == "get_weather":
city = arguments["city"]
# Simulated weather data - in production, call a weather API
weather_data = {
"temperature": 22.5,
"condition": "partly cloudy",
"humidity": 65,
"city": city, # Include the requested city
}
# low-level server will validate structured output against the tool's
# output schema, and additionally serialize it into a TextContent block
# for backwards compatibility with pre-2025-06-18 clients.
return weather_data
else:
raise ValueError(f"Unknown tool: {name}")
async def run():
"""Run the structured output server."""
async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
await server.run(
read_stream,
write_stream,
InitializationOptions(
server_name="structured-output-example",
server_version="0.1.0",
capabilities=server.get_capabilities(
notification_options=NotificationOptions(),
experimental_capabilities={},
),
),
)
if __name__ == "__main__":
asyncio.run(run())
```
_Full example: [examples/snippets/servers/lowlevel/structured_output.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/lowlevel/structured_output.py)_
<!-- /snippet-source -->
Tools can return data in four ways:
1. **Content only**: Return a list of content blocks (default behavior before spec revision 2025-06-18)
2. **Structured data only**: Return a dictionary that will be serialized to JSON (Introduced in spec revision 2025-06-18)
3. **Both**: Return a tuple of (content, structured_data) preferred option to use for backwards compatibility
4. **Direct CallToolResult**: Return `CallToolResult` directly for full control (including `_meta` field)
When an `outputSchema` is defined, the server automatically validates the structured output against the schema. This ensures type safety and helps catch errors early.
##### Returning CallToolResult Directly
For full control over the response including the `_meta` field (for passing data to client applications without exposing it to the model), return `CallToolResult` directly:
<!-- snippet-source examples/snippets/servers/lowlevel/direct_call_tool_result.py -->
```python
"""
Run from the repository root:
uv run examples/snippets/servers/lowlevel/direct_call_tool_result.py
"""
import asyncio
from typing import Any
import mcp.server.stdio
import mcp.types as types
from mcp.server.lowlevel import NotificationOptions, Server
from mcp.server.models import InitializationOptions
server = Server("example-server")
@server.list_tools()
async def list_tools() -> list[types.Tool]:
"""List available tools."""
return [
types.Tool(
name="advanced_tool",
description="Tool with full control including _meta field",
inputSchema={
"type": "object",
"properties": {"message": {"type": "string"}},
"required": ["message"],
},
)
]
@server.call_tool()
async def handle_call_tool(name: str, arguments: dict[str, Any]) -> types.CallToolResult:
"""Handle tool calls by returning CallToolResult directly."""
if name == "advanced_tool":
message = str(arguments.get("message", ""))
return types.CallToolResult(
content=[types.TextContent(type="text", text=f"Processed: {message}")],
structuredContent={"result": "success", "message": message},
_meta={"hidden": "data for client applications only"},
)
raise ValueError(f"Unknown tool: {name}")
async def run():
"""Run the server."""
async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
await server.run(
read_stream,
write_stream,
InitializationOptions(
server_name="example",
server_version="0.1.0",
capabilities=server.get_capabilities(
notification_options=NotificationOptions(),
experimental_capabilities={},
),
),
)
if __name__ == "__main__":
asyncio.run(run())
```
_Full example: [examples/snippets/servers/lowlevel/direct_call_tool_result.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/lowlevel/direct_call_tool_result.py)_
<!-- /snippet-source -->
**Note:** When returning `CallToolResult`, you bypass the automatic content/structured conversion. You must construct the complete response yourself.
### Pagination (Advanced)
For servers that need to handle large datasets, the low-level server provides paginated versions of list operations. This is an optional optimization - most servers won't need pagination unless they're dealing with hundreds or thousands of items.
#### Server-side Implementation
<!-- snippet-source examples/snippets/servers/pagination_example.py -->
```python
"""
Example of implementing pagination with MCP server decorators.
"""
from pydantic import AnyUrl
import mcp.types as types
from mcp.server.lowlevel import Server
# Initialize the server
server = Server("paginated-server")
# Sample data to paginate
ITEMS = [f"Item {i}" for i in range(1, 101)] # 100 items
@server.list_resources()
async def list_resources_paginated(request: types.ListResourcesRequest) -> types.ListResourcesResult:
"""List resources with pagination support."""
page_size = 10
# Extract cursor from request params
cursor = request.params.cursor if request.params is not None else None
# Parse cursor to get offset
start = 0 if cursor is None else int(cursor)
end = start + page_size
# Get page of resources
page_items = [
types.Resource(uri=AnyUrl(f"resource://items/{item}"), name=item, description=f"Description for {item}")
for item in ITEMS[start:end]
]
# Determine next cursor
next_cursor = str(end) if end < len(ITEMS) else None
return types.ListResourcesResult(resources=page_items, nextCursor=next_cursor)
```
_Full example: [examples/snippets/servers/pagination_example.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/pagination_example.py)_
<!-- /snippet-source -->
#### Client-side Consumption
<!-- snippet-source examples/snippets/clients/pagination_client.py -->
```python
"""
Example of consuming paginated MCP endpoints from a client.
"""
import asyncio
from mcp.client.session import ClientSession
from mcp.client.stdio import StdioServerParameters, stdio_client
from mcp.types import PaginatedRequestParams, Resource
async def list_all_resources() -> None:
"""Fetch all resources using pagination."""
async with stdio_client(StdioServerParameters(command="uv", args=["run", "mcp-simple-pagination"])) as (
read,
write,
):
async with ClientSession(read, write) as session:
await session.initialize()
all_resources: list[Resource] = []
cursor = None
while True:
# Fetch a page of resources
result = await session.list_resources(params=PaginatedRequestParams(cursor=cursor))
all_resources.extend(result.resources)
print(f"Fetched {len(result.resources)} resources")
# Check if there are more pages
if result.nextCursor:
cursor = result.nextCursor
else:
break
print(f"Total resources: {len(all_resources)}")
if __name__ == "__main__":
asyncio.run(list_all_resources())
```
_Full example: [examples/snippets/clients/pagination_client.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/clients/pagination_client.py)_
<!-- /snippet-source -->
#### Key Points
- **Cursors are opaque strings** - the server defines the format (numeric offsets, timestamps, etc.)
- **Return `nextCursor=None`** when there are no more pages
- **Backward compatible** - clients that don't support pagination will still work (they'll just get the first page)
- **Flexible page sizes** - Each endpoint can define its own page size based on data characteristics
See the [simple-pagination example](examples/servers/simple-pagination) for a complete implementation.
### Writing MCP Clients
The SDK provides a high-level client interface for connecting to MCP servers using various [transports](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports):
<!-- snippet-source examples/snippets/clients/stdio_client.py -->
```python
"""
cd to the `examples/snippets/clients` directory and run:
uv run client
"""
import asyncio
import os
from pydantic import AnyUrl
from mcp import ClientSession, StdioServerParameters, types
from mcp.client.stdio import stdio_client
from mcp.shared.context import RequestContext
# Create server parameters for stdio connection
server_params = StdioServerParameters(
command="uv", # Using uv to run the server
args=["run", "server", "fastmcp_quickstart", "stdio"], # We're already in snippets dir
env={"UV_INDEX": os.environ.get("UV_INDEX", "")},
)
# Optional: create a sampling callback
async def handle_sampling_message(
context: RequestContext[ClientSession, None], params: types.CreateMessageRequestParams
) -> types.CreateMessageResult:
print(f"Sampling request: {params.messages}")
return types.CreateMessageResult(
role="assistant",
content=types.TextContent(
type="text",
text="Hello, world! from model",
),
model="gpt-3.5-turbo",
stopReason="endTurn",
)
async def run():
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write, sampling_callback=handle_sampling_message) as session:
# Initialize the connection
await session.initialize()
# List available prompts
prompts = await session.list_prompts()
print(f"Available prompts: {[p.name for p in prompts.prompts]}")
# Get a prompt (greet_user prompt from fastmcp_quickstart)
if prompts.prompts:
prompt = await session.get_prompt("greet_user", arguments={"name": "Alice", "style": "friendly"})
print(f"Prompt result: {prompt.messages[0].content}")
# List available resources
resources = await session.list_resources()
print(f"Available resources: {[r.uri for r in resources.resources]}")
# List available tools
tools = await session.list_tools()
print(f"Available tools: {[t.name for t in tools.tools]}")
# Read a resource (greeting resource from fastmcp_quickstart)
resource_content = await session.read_resource(AnyUrl("greeting://World"))
content_block = resource_content.contents[0]
if isinstance(content_block, types.TextContent):
print(f"Resource content: {content_block.text}")
# Call a tool (add tool from fastmcp_quickstart)
result = await session.call_tool("add", arguments={"a": 5, "b": 3})
result_unstructured = result.content[0]
if isinstance(result_unstructured, types.TextContent):
print(f"Tool result: {result_unstructured.text}")
result_structured = result.structuredContent
print(f"Structured tool result: {result_structured}")
def main():
"""Entry point for the client script."""
asyncio.run(run())
if __name__ == "__main__":
main()
```
_Full example: [examples/snippets/clients/stdio_client.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/clients/stdio_client.py)_
<!-- /snippet-source -->
Clients can also connect using [Streamable HTTP transport](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http):
<!-- snippet-source examples/snippets/clients/streamable_basic.py -->
```python
"""
Run from the repository root:
uv run examples/snippets/clients/streamable_basic.py
"""
import asyncio
from mcp import ClientSession
from mcp.client.streamable_http import streamable_http_client
async def main():
# Connect to a streamable HTTP server
async with streamable_http_client("http://localhost:8000/mcp") as (
read_stream,
write_stream,
_,
):
# Create a session using the client streams
async with ClientSession(read_stream, write_stream) as session:
# Initialize the connection
await session.initialize()
# List available tools
tools = await session.list_tools()
print(f"Available tools: {[tool.name for tool in tools.tools]}")
if __name__ == "__main__":
asyncio.run(main())
```
_Full example: [examples/snippets/clients/streamable_basic.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/clients/streamable_basic.py)_
<!-- /snippet-source -->
### Client Display Utilities
When building MCP clients, the SDK provides utilities to help display human-readable names for tools, resources, and prompts:
<!-- snippet-source examples/snippets/clients/display_utilities.py -->
```python
"""
cd to the `examples/snippets` directory and run:
uv run display-utilities-client
"""
import asyncio
import os
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
from mcp.shared.metadata_utils import get_display_name
# Create server parameters for stdio connection
server_params = StdioServerParameters(
command="uv", # Using uv to run the server
args=["run", "server", "fastmcp_quickstart", "stdio"],
env={"UV_INDEX": os.environ.get("UV_INDEX", "")},
)
async def display_tools(session: ClientSession):
"""Display available tools with human-readable names"""
tools_response = await session.list_tools()
for tool in tools_response.tools:
# get_display_name() returns the title if available, otherwise the name
display_name = get_display_name(tool)
print(f"Tool: {display_name}")
if tool.description:
print(f" {tool.description}")
async def display_resources(session: ClientSession):
"""Display available resources with human-readable names"""
resources_response = await session.list_resources()
for resource in resources_response.resources:
display_name = get_display_name(resource)
print(f"Resource: {display_name} ({resource.uri})")
templates_response = await session.list_resource_templates()
for template in templates_response.resourceTemplates:
display_name = get_display_name(template)
print(f"Resource Template: {display_name}")
async def run():
"""Run the display utilities example."""
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
# Initialize the connection
await session.initialize()
print("=== Available Tools ===")
await display_tools(session)
print("\n=== Available Resources ===")
await display_resources(session)
def main():
"""Entry point for the display utilities client."""
asyncio.run(run())
if __name__ == "__main__":
main()
```
_Full example: [examples/snippets/clients/display_utilities.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/clients/display_utilities.py)_
<!-- /snippet-source -->
The `get_display_name()` function implements the proper precedence rules for displaying names:
- For tools: `title` > `annotations.title` > `name`
- For other objects: `title` > `name`
This ensures your client UI shows the most user-friendly names that servers provide.
### OAuth Authentication for Clients
The SDK includes [authorization support](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization) for connecting to protected MCP servers:
<!-- snippet-source examples/snippets/clients/oauth_client.py -->
```python
"""
Before running, specify running MCP RS server URL.
To spin up RS server locally, see
examples/servers/simple-auth/README.md
cd to the `examples/snippets` directory and run:
uv run oauth-client
"""
import asyncio
from urllib.parse import parse_qs, urlparse
import httpx
from pydantic import AnyUrl
from mcp import ClientSession
from mcp.client.auth import OAuthClientProvider, TokenStorage
from mcp.client.streamable_http import streamable_http_client
from mcp.shared.auth import OAuthClientInformationFull, OAuthClientMetadata, OAuthToken
class InMemoryTokenStorage(TokenStorage):
"""Demo In-memory token storage implementation."""
def __init__(self):
self.tokens: OAuthToken | None = None
self.client_info: OAuthClientInformationFull | None = None
async def get_tokens(self) -> OAuthToken | None:
"""Get stored tokens."""
return self.tokens
async def set_tokens(self, tokens: OAuthToken) -> None:
"""Store tokens."""
self.tokens = tokens
async def get_client_info(self) -> OAuthClientInformationFull | None:
"""Get stored client information."""
return self.client_info
async def set_client_info(self, client_info: OAuthClientInformationFull) -> None:
"""Store client information."""
self.client_info = client_info
async def handle_redirect(auth_url: str) -> None:
print(f"Visit: {auth_url}")
async def handle_callback() -> tuple[str, str | None]:
callback_url = input("Paste callback URL: ")
params = parse_qs(urlparse(callback_url).query)
return params["code"][0], params.get("state", [None])[0]
async def main():
"""Run the OAuth client example."""
oauth_auth = OAuthClientProvider(
server_url="http://localhost:8001",
client_metadata=OAuthClientMetadata(
client_name="Example MCP Client",
redirect_uris=[AnyUrl("http://localhost:3000/callback")],
grant_types=["authorization_code", "refresh_token"],
response_types=["code"],
scope="user",
),
storage=InMemoryTokenStorage(),
redirect_handler=handle_redirect,
callback_handler=handle_callback,
)
async with httpx.AsyncClient(auth=oauth_auth, follow_redirects=True) as custom_client:
async with streamable_http_client("http://localhost:8001/mcp", http_client=custom_client) as (read, write, _):
async with ClientSession(read, write) as session:
await session.initialize()
tools = await session.list_tools()
print(f"Available tools: {[tool.name for tool in tools.tools]}")
resources = await session.list_resources()
print(f"Available resources: {[r.uri for r in resources.resources]}")
def run():
asyncio.run(main())
if __name__ == "__main__":
run()
```
_Full example: [examples/snippets/clients/oauth_client.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/clients/oauth_client.py)_
<!-- /snippet-source -->
For a complete working example, see [`examples/clients/simple-auth-client/`](examples/clients/simple-auth-client/).
### Parsing Tool Results
When calling tools through MCP, the `CallToolResult` object contains the tool's response in a structured format. Understanding how to parse this result is essential for properly handling tool outputs.
```python
"""examples/snippets/clients/parsing_tool_results.py"""
import asyncio
from mcp import ClientSession, StdioServerParameters, types
from mcp.client.stdio import stdio_client
async def parse_tool_results():
"""Demonstrates how to parse different types of content in CallToolResult."""
server_params = StdioServerParameters(
command="python", args=["path/to/mcp_server.py"]
)
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
# Example 1: Parsing text content
result = await session.call_tool("get_data", {"format": "text"})
for content in result.content:
if isinstance(content, types.TextContent):
print(f"Text: {content.text}")
# Example 2: Parsing structured content from JSON tools
result = await session.call_tool("get_user", {"id": "123"})
if hasattr(result, "structuredContent") and result.structuredContent:
# Access structured data directly
user_data = result.structuredContent
print(f"User: {user_data.get('name')}, Age: {user_data.get('age')}")
# Example 3: Parsing embedded resources
result = await session.call_tool("read_config", {})
for content in result.content:
if isinstance(content, types.EmbeddedResource):
resource = content.resource
if isinstance(resource, types.TextResourceContents):
print(f"Config from {resource.uri}: {resource.text}")
elif isinstance(resource, types.BlobResourceContents):
print(f"Binary data from {resource.uri}")
# Example 4: Parsing image content
result = await session.call_tool("generate_chart", {"data": [1, 2, 3]})
for content in result.content:
if isinstance(content, types.ImageContent):
print(f"Image ({content.mimeType}): {len(content.data)} bytes")
# Example 5: Handling errors
result = await session.call_tool("failing_tool", {})
if result.isError:
print("Tool execution failed!")
for content in result.content:
if isinstance(content, types.TextContent):
print(f"Error: {content.text}")
async def main():
await parse_tool_results()
if __name__ == "__main__":
asyncio.run(main())
```
### MCP Primitives
The MCP protocol defines three core primitives that servers can implement:
| Primitive | Control | Description | Example Use |
|-----------|-----------------------|-----------------------------------------------------|------------------------------|
| Prompts | User-controlled | Interactive templates invoked by user choice | Slash commands, menu options |
| Resources | Application-controlled| Contextual data managed by the client application | File contents, API responses |
| Tools | Model-controlled | Functions exposed to the LLM to take actions | API calls, data updates |
### Server Capabilities
MCP servers declare capabilities during initialization:
| Capability | Feature Flag | Description |
|--------------|------------------------------|------------------------------------|
| `prompts` | `listChanged` | Prompt template management |
| `resources` | `subscribe`<br/>`listChanged`| Resource exposure and updates |
| `tools` | `listChanged` | Tool discovery and execution |
| `logging` | - | Server logging configuration |
| `completions`| - | Argument completion suggestions |
## Documentation
- [API Reference](https://modelcontextprotocol.github.io/python-sdk/api/)
- [Experimental Features (Tasks)](https://modelcontextprotocol.github.io/python-sdk/experimental/tasks/)
- [Model Context Protocol documentation](https://modelcontextprotocol.io)
- [Model Context Protocol specification](https://modelcontextprotocol.io/specification/latest)
- [Officially supported servers](https://github.com/modelcontextprotocol/servers)
## Contributing
We are passionate about supporting contributors of all levels of experience and would love to see you get involved in the project. See the [contributing guide](CONTRIBUTING.md) to get started.
## License
This project is licensed under the MIT License - see the LICENSE file for details.
================================================
FILE: README.v2.md
================================================
# MCP Python SDK
<div align="center">
<strong>Python implementation of the Model Context Protocol (MCP)</strong>
[![PyPI][pypi-badge]][pypi-url]
[![MIT licensed][mit-badge]][mit-url]
[![Python Version][python-badge]][python-url]
[![Documentation][docs-badge]][docs-url]
[![Protocol][protocol-badge]][protocol-url]
[![Specification][spec-badge]][spec-url]
</div>
<!-- TODO(v2): Move this content back to README.md when v2 is released -->
> [!IMPORTANT]
> **This documents v2 of the SDK (currently in development, pre-alpha on `main`).**
>
> We anticipate a stable v2 release in Q1 2026. Until then, **v1.x remains the recommended version** for production use. v1.x will continue to receive bug fixes and security updates for at least 6 months after v2 ships to give people time to upgrade.
>
> For v1 documentation (the current stable release), see [`README.md`](README.md).
<!-- omit in toc -->
## Table of Contents
- [MCP Python SDK](#mcp-python-sdk)
- [Overview](#overview)
- [Installation](#installation)
- [Adding MCP to your python project](#adding-mcp-to-your-python-project)
- [Running the standalone MCP development tools](#running-the-standalone-mcp-development-tools)
- [Quickstart](#quickstart)
- [What is MCP?](#what-is-mcp)
- [Core Concepts](#core-concepts)
- [Server](#server)
- [Resources](#resources)
- [Tools](#tools)
- [Structured Output](#structured-output)
- [Prompts](#prompts)
- [Images](#images)
- [Context](#context)
- [Getting Context in Functions](#getting-context-in-functions)
- [Context Properties and Methods](#context-properties-and-methods)
- [Completions](#completions)
- [Elicitation](#elicitation)
- [Sampling](#sampling)
- [Logging and Notifications](#logging-and-notifications)
- [Authentication](#authentication)
- [MCPServer Properties](#mcpserver-properties)
- [Session Properties and Methods](#session-properties-and-methods)
- [Request Context Properties](#request-context-properties)
- [Running Your Server](#running-your-server)
- [Development Mode](#development-mode)
- [Claude Desktop Integration](#claude-desktop-integration)
- [Direct Execution](#direct-execution)
- [Streamable HTTP Transport](#streamable-http-transport)
- [CORS Configuration for Browser-Based Clients](#cors-configuration-for-browser-based-clients)
- [Mounting to an Existing ASGI Server](#mounting-to-an-existing-asgi-server)
- [StreamableHTTP servers](#streamablehttp-servers)
- [Basic mounting](#basic-mounting)
- [Host-based routing](#host-based-routing)
- [Multiple servers with path configuration](#multiple-servers-with-path-configuration)
- [Path configuration at initialization](#path-configuration-at-initialization)
- [SSE servers](#sse-servers)
- [Advanced Usage](#advanced-usage)
- [Low-Level Server](#low-level-server)
- [Structured Output Support](#structured-output-support)
- [Pagination (Advanced)](#pagination-advanced)
- [Writing MCP Clients](#writing-mcp-clients)
- [Client Display Utilities](#client-display-utilities)
- [OAuth Authentication for Clients](#oauth-authentication-for-clients)
- [Parsing Tool Results](#parsing-tool-results)
- [MCP Primitives](#mcp-primitives)
- [Server Capabilities](#server-capabilities)
- [Documentation](#documentation)
- [Contributing](#contributing)
- [License](#license)
[pypi-badge]: https://img.shields.io/pypi/v/mcp.svg
[pypi-url]: https://pypi.org/project/mcp/
[mit-badge]: https://img.shields.io/pypi/l/mcp.svg
[mit-url]: https://github.com/modelcontextprotocol/python-sdk/blob/main/LICENSE
[python-badge]: https://img.shields.io/pypi/pyversions/mcp.svg
[python-url]: https://www.python.org/downloads/
[docs-badge]: https://img.shields.io/badge/docs-python--sdk-blue.svg
[docs-url]: https://modelcontextprotocol.github.io/python-sdk/
[protocol-badge]: https://img.shields.io/badge/protocol-modelcontextprotocol.io-blue.svg
[protocol-url]: https://modelcontextprotocol.io
[spec-badge]: https://img.shields.io/badge/spec-spec.modelcontextprotocol.io-blue.svg
[spec-url]: https://modelcontextprotocol.io/specification/latest
## Overview
The Model Context Protocol allows applications to provide context for LLMs in a standardized way, separating the concerns of providing context from the actual LLM interaction. This Python SDK implements the full MCP specification, making it easy to:
- Build MCP clients that can connect to any MCP server
- Create MCP servers that expose resources, prompts and tools
- Use standard transports like stdio, SSE, and Streamable HTTP
- Handle all MCP protocol messages and lifecycle events
## Installation
### Adding MCP to your python project
We recommend using [uv](https://docs.astral.sh/uv/) to manage your Python projects.
If you haven't created a uv-managed project yet, create one:
```bash
uv init mcp-server-demo
cd mcp-server-demo
```
Then add MCP to your project dependencies:
```bash
uv add "mcp[cli]"
```
Alternatively, for projects using pip for dependencies:
```bash
pip install "mcp[cli]"
```
### Running the standalone MCP development tools
To run the mcp command with uv:
```bash
uv run mcp
```
## Quickstart
Let's create a simple MCP server that exposes a calculator tool and some data:
<!-- snippet-source examples/snippets/servers/mcpserver_quickstart.py -->
```python
"""MCPServer quickstart example.
Run from the repository root:
uv run examples/snippets/servers/mcpserver_quickstart.py
"""
from mcp.server.mcpserver import MCPServer
# Create an MCP server
mcp = MCPServer("Demo")
# Add an addition tool
@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers"""
return a + b
# Add a dynamic greeting resource
@mcp.resource("greeting://{name}")
def get_greeting(name: str) -> str:
"""Get a personalized greeting"""
return f"Hello, {name}!"
# Add a prompt
@mcp.prompt()
def greet_user(name: str, style: str = "friendly") -> str:
"""Generate a greeting prompt"""
styles = {
"friendly": "Please write a warm, friendly greeting",
"formal": "Please write a formal, professional greeting",
"casual": "Please write a casual, relaxed greeting",
}
return f"{styles.get(style, styles['friendly'])} for someone named {name}."
# Run with streamable HTTP transport
if __name__ == "__main__":
mcp.run(transport="streamable-http", json_response=True)
```
_Full example: [examples/snippets/servers/mcpserver_quickstart.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/mcpserver_quickstart.py)_
<!-- /snippet-source -->
You can install this server in [Claude Code](https://docs.claude.com/en/docs/claude-code/mcp) and interact with it right away. First, run the server:
```bash
uv run --with mcp examples/snippets/servers/mcpserver_quickstart.py
```
Then add it to Claude Code:
```bash
claude mcp add --transport http my-server http://localhost:8000/mcp
```
Alternatively, you can test it with the MCP Inspector. Start the server as above, then in a separate terminal:
```bash
npx -y @modelcontextprotocol/inspector
```
In the inspector UI, connect to `http://localhost:8000/mcp`.
## What is MCP?
The [Model Context Protocol (MCP)](https://modelcontextprotocol.io) lets you build servers that expose data and functionality to LLM applications in a secure, standardized way. Think of it like a web API, but specifically designed for LLM interactions. MCP servers can:
- Expose data through **Resources** (think of these sort of like GET endpoints; they are used to load information into the LLM's context)
- Provide functionality through **Tools** (sort of like POST endpoints; they are used to execute code or otherwise produce a side effect)
- Define interaction patterns through **Prompts** (reusable templates for LLM interactions)
- And more!
## Core Concepts
### Server
The MCPServer server is your core interface to the MCP protocol. It handles connection management, protocol compliance, and message routing:
<!-- snippet-source examples/snippets/servers/lifespan_example.py -->
```python
"""Example showing lifespan support for startup/shutdown with strong typing."""
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from dataclasses import dataclass
from mcp.server.mcpserver import Context, MCPServer
# Mock database class for example
class Database:
"""Mock database class for example."""
@classmethod
async def connect(cls) -> "Database":
"""Connect to database."""
return cls()
async def disconnect(self) -> None:
"""Disconnect from database."""
pass
def query(self) -> str:
"""Execute a query."""
return "Query result"
@dataclass
class AppContext:
"""Application context with typed dependencies."""
db: Database
@asynccontextmanager
async def app_lifespan(server: MCPServer) -> AsyncIterator[AppContext]:
"""Manage application lifecycle with type-safe context."""
# Initialize on startup
db = await Database.connect()
try:
yield AppContext(db=db)
finally:
# Cleanup on shutdown
await db.disconnect()
# Pass lifespan to server
mcp = MCPServer("My App", lifespan=app_lifespan)
# Access type-safe lifespan context in tools
@mcp.tool()
def query_db(ctx: Context[AppContext]) -> str:
"""Tool that uses initialized resources."""
db = ctx.request_context.lifespan_context.db
return db.query()
```
_Full example: [examples/snippets/servers/lifespan_example.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/lifespan_example.py)_
<!-- /snippet-source -->
### Resources
Resources are how you expose data to LLMs. They're similar to GET endpoints in a REST API - they provide data but shouldn't perform significant computation or have side effects:
<!-- snippet-source examples/snippets/servers/basic_resource.py -->
```python
from mcp.server.mcpserver import MCPServer
mcp = MCPServer(name="Resource Example")
@mcp.resource("file://documents/{name}")
def read_document(name: str) -> str:
"""Read a document by name."""
# This would normally read from disk
return f"Content of {name}"
@mcp.resource("config://settings")
def get_settings() -> str:
"""Get application settings."""
return """{
"theme": "dark",
"language": "en",
"debug": false
}"""
```
_Full example: [examples/snippets/servers/basic_resource.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/basic_resource.py)_
<!-- /snippet-source -->
### Tools
Tools let LLMs take actions through your server. Unlike resources, tools are expected to perform computation and have side effects:
<!-- snippet-source examples/snippets/servers/basic_tool.py -->
```python
from mcp.server.mcpserver import MCPServer
mcp = MCPServer(name="Tool Example")
@mcp.tool()
def sum(a: int, b: int) -> int:
"""Add two numbers together."""
return a + b
@mcp.tool()
def get_weather(city: str, unit: str = "celsius") -> str:
"""Get weather for a city."""
# This would normally call a weather API
return f"Weather in {city}: 22degrees{unit[0].upper()}"
```
_Full example: [examples/snippets/servers/basic_tool.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/basic_tool.py)_
<!-- /snippet-source -->
Tools can optionally receive a Context object by including a parameter with the `Context` type annotation. This context is automatically injected by the MCPServer framework and provides access to MCP capabilities:
<!-- snippet-source examples/snippets/servers/tool_progress.py -->
```python
from mcp.server.mcpserver import Context, MCPServer
mcp = MCPServer(name="Progress Example")
@mcp.tool()
async def long_running_task(task_name: str, ctx: Context, steps: int = 5) -> str:
"""Execute a task with progress updates."""
await ctx.info(f"Starting: {task_name}")
for i in range(steps):
progress = (i + 1) / steps
await ctx.report_progress(
progress=progress,
total=1.0,
message=f"Step {i + 1}/{steps}",
)
await ctx.debug(f"Completed step {i + 1}")
return f"Task '{task_name}' completed"
```
_Full example: [examples/snippets/servers/tool_progress.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/tool_progress.py)_
<!-- /snippet-source -->
#### Structured Output
Tools will return structured results by default, if their return type
annotation is compatible. Otherwise, they will return unstructured results.
Structured output supports these return types:
- Pydantic models (BaseModel subclasses)
- TypedDicts
- Dataclasses and other classes with type hints
- `dict[str, T]` (where T is any JSON-serializable type)
- Primitive types (str, int, float, bool, bytes, None) - wrapped in `{"result": value}`
- Generic types (list, tuple, Union, Optional, etc.) - wrapped in `{"result": value}`
Classes without type hints cannot be serialized for structured output. Only
classes with properly annotated attributes will be converted to Pydantic models
for schema generation and validation.
Structured results are automatically validated against the output schema
generated from the annotation. This ensures the tool returns well-typed,
validated data that clients can easily process.
**Note:** For backward compatibility, unstructured results are also
returned. Unstructured results are provided for backward compatibility
with previous versions of the MCP specification, and are quirks-compatible
with previous versions of MCPServer in the current version of the SDK.
**Note:** In cases where a tool function's return type annotation
causes the tool to be classified as structured _and this is undesirable_,
the classification can be suppressed by passing `structured_output=False`
to the `@tool` decorator.
##### Advanced: Direct CallToolResult
For full control over tool responses including the `_meta` field (for passing data to client applications without exposing it to the model), you can return `CallToolResult` directly:
<!-- snippet-source examples/snippets/servers/direct_call_tool_result.py -->
```python
"""Example showing direct CallToolResult return for advanced control."""
from typing import Annotated
from pydantic import BaseModel
from mcp.server.mcpserver import MCPServer
from mcp.types import CallToolResult, TextContent
mcp = MCPServer("CallToolResult Example")
class ValidationModel(BaseModel):
"""Model for validating structured output."""
status: str
data: dict[str, int]
@mcp.tool()
def advanced_tool() -> CallToolResult:
"""Return CallToolResult directly for full control including _meta field."""
return CallToolResult(
content=[TextContent(type="text", text="Response visible to the model")],
_meta={"hidden": "data for client applications only"},
)
@mcp.tool()
def validated_tool() -> Annotated[CallToolResult, ValidationModel]:
"""Return CallToolResult with structured output validation."""
return CallToolResult(
content=[TextContent(type="text", text="Validated response")],
structured_content={"status": "success", "data": {"result": 42}},
_meta={"internal": "metadata"},
)
@mcp.tool()
def empty_result_tool() -> CallToolResult:
"""For empty results, return CallToolResult with empty content."""
return CallToolResult(content=[])
```
_Full example: [examples/snippets/servers/direct_call_tool_result.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/direct_call_tool_result.py)_
<!-- /snippet-source -->
**Important:** `CallToolResult` must always be returned (no `Optional` or `Union`). For empty results, use `CallToolResult(content=[])`. For optional simple types, use `str | None` without `CallToolResult`.
<!-- snippet-source examples/snippets/servers/structured_output.py -->
```python
"""Example showing structured output with tools."""
from typing import TypedDict
from pydantic import BaseModel, Field
from mcp.server.mcpserver import MCPServer
mcp = MCPServer("Structured Output Example")
# Using Pydantic models for rich structured data
class WeatherData(BaseModel):
"""Weather information structure."""
temperature: float = Field(description="Temperature in Celsius")
humidity: float = Field(description="Humidity percentage")
condition: str
wind_speed: float
@mcp.tool()
def get_weather(city: str) -> WeatherData:
"""Get weather for a city - returns structured data."""
# Simulated weather data
return WeatherData(
temperature=22.5,
humidity=45.0,
condition="sunny",
wind_speed=5.2,
)
# Using TypedDict for simpler structures
class LocationInfo(TypedDict):
latitude: float
longitude: float
name: str
@mcp.tool()
def get_location(address: str) -> LocationInfo:
"""Get location coordinates"""
return LocationInfo(latitude=51.5074, longitude=-0.1278, name="London, UK")
# Using dict[str, Any] for flexible schemas
@mcp.tool()
def get_statistics(data_type: str) -> dict[str, float]:
"""Get various statistics"""
return {"mean": 42.5, "median": 40.0, "std_dev": 5.2}
# Ordinary classes with type hints work for structured output
class UserProfile:
name: str
age: int
email: str | None = None
def __init__(self, name: str, age: int, email: str | None = None):
self.name = name
self.age = age
self.email = email
@mcp.tool()
def get_user(user_id: str) -> UserProfile:
"""Get user profile - returns structured data"""
return UserProfile(name="Alice", age=30, email="alice@example.com")
# Classes WITHOUT type hints cannot be used for structured output
class UntypedConfig:
def __init__(self, setting1, setting2): # type: ignore[reportMissingParameterType]
self.setting1 = setting1
self.setting2 = setting2
@mcp.tool()
def get_config() -> UntypedConfig:
"""This returns unstructured output - no schema generated"""
return UntypedConfig("value1", "value2")
# Lists and other types are wrapped automatically
@mcp.tool()
def list_cities() -> list[str]:
"""Get a list of cities"""
return ["London", "Paris", "Tokyo"]
# Returns: {"result": ["London", "Paris", "Tokyo"]}
@mcp.tool()
def get_temperature(city: str) -> float:
"""Get temperature as a simple float"""
return 22.5
# Returns: {"result": 22.5}
```
_Full example: [examples/snippets/servers/structured_output.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/structured_output.py)_
<!-- /snippet-source -->
### Prompts
Prompts are reusable templates that help LLMs interact with your server effectively:
<!-- snippet-source examples/snippets/servers/basic_prompt.py -->
```python
from mcp.server.mcpserver import MCPServer
from mcp.server.mcpserver.prompts import base
mcp = MCPServer(name="Prompt Example")
@mcp.prompt(title="Code Review")
def review_code(code: str) -> str:
return f"Please review this code:\n\n{code}"
@mcp.prompt(title="Debug Assistant")
def debug_error(error: str) -> list[base.Message]:
return [
base.UserMessage("I'm seeing this error:"),
base.UserMessage(error),
base.AssistantMessage("I'll help debug that. What have you tried so far?"),
]
```
_Full example: [examples/snippets/servers/basic_prompt.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/basic_prompt.py)_
<!-- /snippet-source -->
### Icons
MCP servers can provide icons for UI display. Icons can be added to the server implementation, tools, resources, and prompts:
```python
from mcp.server.mcpserver import MCPServer, Icon
# Create an icon from a file path or URL
icon = Icon(
src="icon.png",
mimeType="image/png",
sizes="64x64"
)
# Add icons to server
mcp = MCPServer(
"My Server",
website_url="https://example.com",
icons=[icon]
)
# Add icons to tools, resources, and prompts
@mcp.tool(icons=[icon])
def my_tool():
"""Tool with an icon."""
return "result"
@mcp.resource("demo://resource", icons=[icon])
def my_resource():
"""Resource with an icon."""
return "content"
```
_Full example: [examples/mcpserver/icons_demo.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/mcpserver/icons_demo.py)_
### Images
MCPServer provides an `Image` class that automatically handles image data:
<!-- snippet-source examples/snippets/servers/images.py -->
```python
"""Example showing image handling with MCPServer."""
from PIL import Image as PILImage
from mcp.server.mcpserver import Image, MCPServer
mcp = MCPServer("Image Example")
@mcp.tool()
def create_thumbnail(image_path: str) -> Image:
"""Create a thumbnail from an image"""
img = PILImage.open(image_path)
img.thumbnail((100, 100))
return Image(data=img.tobytes(), format="png")
```
_Full example: [examples/snippets/servers/images.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/images.py)_
<!-- /snippet-source -->
### Context
The Context object is automatically injected into tool and resource functions that request it via type hints. It provides access to MCP capabilities like logging, progress reporting, resource reading, user interaction, and request metadata.
#### Getting Context in Functions
To use context in a tool or resource function, add a parameter with the `Context` type annotation:
```python
from mcp.server.mcpserver import Context, MCPServer
mcp = MCPServer(name="Context Example")
@mcp.tool()
async def my_tool(x: int, ctx: Context) -> str:
"""Tool that uses context capabilities."""
# The context parameter can have any name as long as it's type-annotated
return await process_with_context(x, ctx)
```
#### Context Properties and Methods
The Context object provides the following capabilities:
- `ctx.request_id` - Unique ID for the current request
- `ctx.client_id` - Client ID if available
- `ctx.mcp_server` - Access to the MCPServer server instance (see [MCPServer Properties](#mcpserver-properties))
- `ctx.session` - Access to the underlying session for advanced communication (see [Session Properties and Methods](#session-properties-and-methods))
- `ctx.request_context` - Access to request-specific data and lifespan resources (see [Request Context Properties](#request-context-properties))
- `await ctx.debug(message)` - Send debug log message
- `await ctx.info(message)` - Send info log message
- `await ctx.warning(message)` - Send warning log message
- `await ctx.error(message)` - Send error log message
- `await ctx.log(level, message, logger_name=None)` - Send log with custom level
- `await ctx.report_progress(progress, total=None, message=None)` - Report operation progress
- `await ctx.read_resource(uri)` - Read a resource by URI
- `await ctx.elicit(message, schema)` - Request additional information from user with validation
<!-- snippet-source examples/snippets/servers/tool_progress.py -->
```python
from mcp.server.mcpserver import Context, MCPServer
mcp = MCPServer(name="Progress Example")
@mcp.tool()
async def long_running_task(task_name: str, ctx: Context, steps: int = 5) -> str:
"""Execute a task with progress updates."""
await ctx.info(f"Starting: {task_name}")
for i in range(steps):
progress = (i + 1) / steps
await ctx.report_progress(
progress=progress,
total=1.0,
message=f"Step {i + 1}/{steps}",
)
await ctx.debug(f"Completed step {i + 1}")
return f"Task '{task_name}' completed"
```
_Full example: [examples/snippets/servers/tool_progress.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/tool_progress.py)_
<!-- /snippet-source -->
### Completions
MCP supports providing completion suggestions for prompt arguments and resource template parameters. With the context parameter, servers can provide completions based on previously resolved values:
Client usage:
<!-- snippet-source examples/snippets/clients/completion_client.py -->
```python
"""cd to the `examples/snippets` directory and run:
uv run completion-client
"""
import asyncio
import os
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
from mcp.types import PromptReference, ResourceTemplateReference
# Create server parameters for stdio connection
server_params = StdioServerParameters(
command="uv", # Using uv to run the server
args=["run", "server", "completion", "stdio"], # Server with completion support
env={"UV_INDEX": os.environ.get("UV_INDEX", "")},
)
async def run():
"""Run the completion client example."""
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
# Initialize the connection
await session.initialize()
# List available resource templates
templates = await session.list_resource_templates()
print("Available resource templates:")
for template in templates.resource_templates:
print(f" - {template.uri_template}")
# List available prompts
prompts = await session.list_prompts()
print("\nAvailable prompts:")
for prompt in prompts.prompts:
print(f" - {prompt.name}")
# Complete resource template arguments
if templates.resource_templates:
template = templates.resource_templates[0]
print(f"\nCompleting arguments for resource template: {template.uri_template}")
# Complete without context
result = await session.complete(
ref=ResourceTemplateReference(type="ref/resource", uri=template.uri_template),
argument={"name": "owner", "value": "model"},
)
print(f"Completions for 'owner' starting with 'model': {result.completion.values}")
# Complete with context - repo suggestions based on owner
result = await session.complete(
ref=ResourceTemplateReference(type="ref/resource", uri=template.uri_template),
argument={"name": "repo", "value": ""},
context_arguments={"owner": "modelcontextprotocol"},
)
print(f"Completions for 'repo' with owner='modelcontextprotocol': {result.completion.values}")
# Complete prompt arguments
if prompts.prompts:
prompt_name = prompts.prompts[0].name
print(f"\nCompleting arguments for prompt: {prompt_name}")
result = await session.complete(
ref=PromptReference(type="ref/prompt", name=prompt_name),
argument={"name": "style", "value": ""},
)
print(f"Completions for 'style' argument: {result.completion.values}")
def main():
"""Entry point for the completion client."""
asyncio.run(run())
if __name__ == "__main__":
main()
```
_Full example: [examples/snippets/clients/completion_client.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/clients/completion_client.py)_
<!-- /snippet-source -->
### Elicitation
Request additional information from users. This example shows an Elicitation during a Tool Call:
<!-- snippet-source examples/snippets/servers/elicitation.py -->
```python
"""Elicitation examples demonstrating form and URL mode elicitation.
Form mode elicitation collects structured, non-sensitive data through a schema.
URL mode elicitation directs users to external URLs for sensitive operations
like OAuth flows, credential collection, or payment processing.
"""
import uuid
from pydantic import BaseModel, Field
from mcp.server.mcpserver import Context, MCPServer
from mcp.shared.exceptions import UrlElicitationRequiredError
from mcp.types import ElicitRequestURLParams
mcp = MCPServer(name="Elicitation Example")
class BookingPreferences(BaseModel):
"""Schema for collecting user preferences."""
checkAlternative: bool = Field(description="Would you like to check another date?")
alternativeDate: str = Field(
default="2024-12-26",
description="Alternative date (YYYY-MM-DD)",
)
@mcp.tool()
async def book_table(date: str, time: str, party_size: int, ctx: Context) -> str:
"""Book a table with date availability check.
This demonstrates form mode elicitation for collecting non-sensitive user input.
"""
# Check if date is available
if date == "2024-12-25":
# Date unavailable - ask user for alternative
result = await ctx.elicit(
message=(f"No tables available for {party_size} on {date}. Would you like to try another date?"),
schema=BookingPreferences,
)
if result.action == "accept" and result.data:
if result.data.checkAlternative:
return f"[SUCCESS] Booked for {result.data.alternativeDate}"
return "[CANCELLED] No booking made"
return "[CANCELLED] Booking cancelled"
# Date available
return f"[SUCCESS] Booked for {date} at {time}"
@mcp.tool()
async def secure_payment(amount: float, ctx: Context) -> str:
"""Process a secure payment requiring URL confirmation.
This demonstrates URL mode elicitation using ctx.elicit_url() for
operations that require out-of-band user interaction.
"""
elicitation_id = str(uuid.uuid4())
result = await ctx.elicit_url(
message=f"Please confirm payment of ${amount:.2f}",
url=f"https://payments.example.com/confirm?amount={amount}&id={elicitation_id}",
elicitation_id=elicitation_id,
)
if result.action == "accept":
# In a real app, the payment confirmation would happen out-of-band
# and you'd verify the payment status from your backend
return f"Payment of ${amount:.2f} initiated - check your browser to complete"
elif result.action == "decline":
return "Payment declined by user"
return "Payment cancelled"
@mcp.tool()
async def connect_service(service_name: str, ctx: Context) -> str:
"""Connect to a third-party service requiring OAuth authorization.
This demonstrates the "throw error" pattern using UrlElicitationRequiredError.
Use this pattern when the tool cannot proceed without user authorization.
"""
elicitation_id = str(uuid.uuid4())
# Raise UrlElicitationRequiredError to signal that the client must complete
# a URL elicitation before this request can be processed.
# The MCP framework will convert this to a -32042 error response.
raise UrlElicitationRequiredError(
[
ElicitRequestURLParams(
mode="url",
message=f"Authorization required to connect to {service_name}",
url=f"https://{service_name}.example.com/oauth/authorize?elicit={elicitation_id}",
elicitation_id=elicitation_id,
)
]
)
```
_Full example: [examples/snippets/servers/elicitation.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/elicitation.py)_
<!-- /snippet-source -->
Elicitation schemas support default values for all field types. Default values are automatically included in the JSON schema sent to clients, allowing them to pre-populate forms.
The `elicit()` method returns an `ElicitationResult` with:
- `action`: "accept", "decline", or "cancel"
- `data`: The validated response (only when accepted)
- `validation_error`: Any validation error message
### Sampling
Tools can interact with LLMs through sampling (generating text):
<!-- snippet-source examples/snippets/servers/sampling.py -->
```python
from mcp.server.mcpserver import Context, MCPServer
from mcp.types import SamplingMessage, TextContent
mcp = MCPServer(name="Sampling Example")
@mcp.tool()
async def generate_poem(topic: str, ctx: Context) -> str:
"""Generate a poem using LLM sampling."""
prompt = f"Write a short poem about {topic}"
result = await ctx.session.create_message(
messages=[
SamplingMessage(
role="user",
content=TextContent(type="text", text=prompt),
)
],
max_tokens=100,
)
# Since we're not passing tools param, result.content is single content
if result.content.type == "text":
return result.content.text
return str(result.content)
```
_Full example: [examples/snippets/servers/sampling.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/sampling.py)_
<!-- /snippet-source -->
### Logging and Notifications
Tools can send logs and notifications through the context:
<!-- snippet-source examples/snippets/servers/notifications.py -->
```python
from mcp.server.mcpserver import Context, MCPServer
mcp = MCPServer(name="Notifications Example")
@mcp.tool()
async def process_data(data: str, ctx: Context) -> str:
"""Process data with logging."""
# Different log levels
await ctx.debug(f"Debug: Processing '{data}'")
await ctx.info("Info: Starting processing")
await ctx.warning("Warning: This is experimental")
await ctx.error("Error: (This is just a demo)")
# Notify about resource changes
await ctx.session.send_resource_list_changed()
return f"Processed: {data}"
```
_Full example: [examples/snippets/servers/notifications.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/notifications.py)_
<!-- /snippet-source -->
### Authentication
Authentication can be used by servers that want to expose tools accessing protected resources.
`mcp.server.auth` implements OAuth 2.1 resource server functionality, where MCP servers act as Resource Servers (RS) that validate tokens issued by separate Authorization Servers (AS). This follows the [MCP authorization specification](https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization) and implements RFC 9728 (Protected Resource Metadata) for AS discovery.
MCP servers can use authentication by providing an implementation of the `TokenVerifier` protocol:
<!-- snippet-source examples/snippets/servers/oauth_server.py -->
```python
"""Run from the repository root:
uv run examples/snippets/servers/oauth_server.py
"""
from pydantic import AnyHttpUrl
from mcp.server.auth.provider import AccessToken, TokenVerifier
from mcp.server.auth.settings import AuthSettings
from mcp.server.mcpserver import MCPServer
class SimpleTokenVerifier(TokenVerifier):
"""Simple token verifier for demonstration."""
async def verify_token(self, token: str) -> AccessToken | None:
pass # This is where you would implement actual token validation
# Create MCPServer instance as a Resource Server
mcp = MCPServer(
"Weather Service",
# Token verifier for authentication
token_verifier=SimpleTokenVerifier(),
# Auth settings for RFC 9728 Protected Resource Metadata
auth=AuthSettings(
issuer_url=AnyHttpUrl("https://auth.example.com"), # Authorization Server URL
resource_server_url=AnyHttpUrl("http://localhost:3001"), # This server's URL
required_scopes=["user"],
),
)
@mcp.tool()
async def get_weather(city: str = "London") -> dict[str, str]:
"""Get weather data for a city"""
return {
"city": city,
"temperature": "22",
"condition": "Partly cloudy",
"humidity": "65%",
}
if __name__ == "__main__":
mcp.run(transport="streamable-http", json_response=True)
```
_Full example: [examples/snippets/servers/oauth_server.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/oauth_server.py)_
<!-- /snippet-source -->
For a complete example with separate Authorization Server and Resource Server implementations, see [`examples/servers/simple-auth/`](examples/servers/simple-auth/).
**Architecture:**
- **Authorization Server (AS)**: Handles OAuth flows, user authentication, and token issuance
- **Resource Server (RS)**: Your MCP server that validates tokens and serves protected resources
- **Client**: Discovers AS through RFC 9728, obtains tokens, and uses them with the MCP server
See [TokenVerifier](src/mcp/server/auth/provider.py) for more details on implementing token validation.
### MCPServer Properties
The MCPServer server instance accessible via `ctx.mcp_server` provides access to server configuration and metadata:
- `ctx.mcp_server.name` - The server's name as defined during initialization
- `ctx.mcp_server.instructions` - Server instructions/description provided to clients
- `ctx.mcp_server.website_url` - Optional website URL for the server
- `ctx.mcp_server.icons` - Optional list of icons for UI display
- `ctx.mcp_server.settings` - Complete server configuration object containing:
- `debug` - Debug mode flag
- `log_level` - Current logging level
- `host` and `port` - Server network configuration
- `sse_path`, `streamable_http_path` - Transport paths
- `stateless_http` - Whether the server operates in stateless mode
- And other configuration options
```python
@mcp.tool()
def server_info(ctx: Context) -> dict:
"""Get information about the current server."""
return {
"name": ctx.mcp_server.name,
"instructions": ctx.mcp_server.instructions,
"debug_mode": ctx.mcp_server.settings.debug,
"log_level": ctx.mcp_server.settings.log_level,
"host": ctx.mcp_server.settings.host,
"port": ctx.mcp_server.settings.port,
}
```
### Session Properties and Methods
The session object accessible via `ctx.session` provides advanced control over client communication:
- `ctx.session.client_params` - Client initialization parameters and declared capabilities
- `await ctx.session.send_log_message(level, data, logger)` - Send log messages with full control
- `await ctx.session.create_message(messages, max_tokens)` - Request LLM sampling/completion
- `await ctx.session.send_progress_notification(token, progress, total, message)` - Direct progress updates
- `await ctx.session.send_resource_updated(uri)` - Notify clients that a specific resource changed
- `await ctx.session.send_resource_list_changed()` - Notify clients that the resource list changed
- `await ctx.session.send_tool_list_changed()` - Notify clients that the tool list changed
- `await ctx.session.send_prompt_list_changed()` - Notify clients that the prompt list changed
```python
@mcp.tool()
async def notify_data_update(resource_uri: str, ctx: Context) -> str:
"""Update data and notify clients of the change."""
# Perform data update logic here
# Notify clients that this specific resource changed
await ctx.session.send_resource_updated(AnyUrl(resource_uri))
# If this affects the overall resource list, notify about that too
await ctx.session.send_resource_list_changed()
return f"Updated {resource_uri} and notified clients"
```
### Request Context Properties
The request context accessible via `ctx.request_context` contains request-specific information and resources:
- `ctx.request_context.lifespan_context` - Access to resources initialized during server startup
- Database connections, configuration objects, shared services
- Type-safe access to resources defined in your server's lifespan function
- `ctx.request_context.meta` - Request metadata from the client including:
- `progressToken` - Token for progress notifications
- Other client-provided metadata
- `ctx.request_context.request` - The original MCP request object for advanced processing
- `ctx.request_context.request_id` - Unique identifier for this request
```python
# Example with typed lifespan context
@dataclass
class AppContext:
db: Database
config: AppConfig
@mcp.tool()
def query_with_config(query: str, ctx: Context) -> str:
"""Execute a query using shared database and configuration."""
# Access typed lifespan context
app_ctx: AppContext = ctx.request_context.lifespan_context
# Use shared resources
connection = app_ctx.db
settings = app_ctx.config
# Execute query with configuration
result = connection.execute(query, timeout=settings.query_timeout)
return str(result)
```
_Full lifespan example: [examples/snippets/servers/lifespan_example.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/lifespan_example.py)_
## Running Your Server
### Development Mode
The fastest way to test and debug your server is with the MCP Inspector:
```bash
uv run mcp dev server.py
# Add dependencies
uv run mcp dev server.py --with pandas --with numpy
# Mount local code
uv run mcp dev server.py --with-editable .
```
### Claude Desktop Integration
Once your server is ready, install it in Claude Desktop:
```bash
uv run mcp install server.py
# Custom name
uv run mcp install server.py --name "My Analytics Server"
# Environment variables
uv run mcp install server.py -v API_KEY=abc123 -v DB_URL=postgres://...
uv run mcp install server.py -f .env
```
### Direct Execution
For advanced scenarios like custom deployments:
<!-- snippet-source examples/snippets/servers/direct_execution.py -->
```python
"""Example showing direct execution of an MCP server.
This is the simplest way to run an MCP server directly.
cd to the `examples/snippets` directory and run:
uv run direct-execution-server
or
python servers/direct_execution.py
"""
from mcp.server.mcpserver import MCPServer
mcp = MCPServer("My App")
@mcp.tool()
def hello(name: str = "World") -> str:
"""Say hello to someone."""
return f"Hello, {name}!"
def main():
"""Entry point for the direct execution server."""
mcp.run()
if __name__ == "__main__":
main()
```
_Full example: [examples/snippets/servers/direct_execution.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/direct_execution.py)_
<!-- /snippet-source -->
Run it with:
```bash
python servers/direct_execution.py
# or
uv run mcp run servers/direct_execution.py
```
Note that `uv run mcp run` or `uv run mcp dev` only supports server using MCPServer and not the low-level server variant.
### Streamable HTTP Transport
> **Note**: Streamable HTTP transport is the recommended transport for production deployments. Use `stateless_http=True` and `json_response=True` for optimal scalability.
<!-- snippet-source examples/snippets/servers/streamable_config.py -->
```python
"""Run from the repository root:
uv run examples/snippets/servers/streamable_config.py
"""
from mcp.server.mcpserver import MCPServer
mcp = MCPServer("StatelessServer")
# Add a simple tool to demonstrate the server
@mcp.tool()
def greet(name: str = "World") -> str:
"""Greet someone by name."""
return f"Hello, {name}!"
# Run server with streamable_http transport
# Transport-specific options (stateless_http, json_response) are passed to run()
if __name__ == "__main__":
# Stateless server with JSON responses (recommended)
mcp.run(transport="streamable-http", stateless_http=True, json_response=True)
# Other configuration options:
# Stateless server with SSE streaming responses
# mcp.run(transport="streamable-http", stateless_http=True)
# Stateful server with session persistence
# mcp.run(transport="streamable-http")
```
_Full example: [examples/snippets/servers/streamable_config.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/streamable_config.py)_
<!-- /snippet-source -->
You can mount multiple MCPServer servers in a Starlette application:
<!-- snippet-source examples/snippets/servers/streamable_starlette_mount.py -->
```python
"""Run from the repository root:
uvicorn examples.snippets.servers.streamable_starlette_mount:app --reload
"""
import contextlib
from starlette.a
gitextract_oto7xmdg/
├── .claude/
│ └── commands/
│ └── review-pr.md
├── .git-blame-ignore-revs
├── .gitattribute
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug.yaml
│ │ ├── config.yaml
│ │ ├── feature-request.yaml
│ │ └── question.yaml
│ ├── actions/
│ │ └── conformance/
│ │ ├── client.py
│ │ └── run-server.sh
│ ├── dependabot.yml
│ └── workflows/
│ ├── claude-code-review.yml
│ ├── claude.yml
│ ├── comment-on-release.yml
│ ├── conformance.yml
│ ├── main.yml
│ ├── publish-docs-manually.yml
│ ├── publish-pypi.yml
│ ├── shared.yml
│ └── weekly-lockfile-update.yml
├── .gitignore
├── .pre-commit-config.yaml
├── CLAUDE.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── README.v2.md
├── RELEASE.md
├── SECURITY.md
├── docs/
│ ├── authorization.md
│ ├── concepts.md
│ ├── experimental/
│ │ ├── index.md
│ │ ├── tasks-client.md
│ │ ├── tasks-server.md
│ │ └── tasks.md
│ ├── hooks/
│ │ └── gen_ref_pages.py
│ ├── index.md
│ ├── installation.md
│ ├── low-level-server.md
│ ├── migration.md
│ └── testing.md
├── examples/
│ ├── README.md
│ ├── clients/
│ │ ├── simple-auth-client/
│ │ │ ├── README.md
│ │ │ ├── mcp_simple_auth_client/
│ │ │ │ ├── __init__.py
│ │ │ │ └── main.py
│ │ │ └── pyproject.toml
│ │ ├── simple-chatbot/
│ │ │ ├── README.MD
│ │ │ ├── mcp_simple_chatbot/
│ │ │ │ ├── main.py
│ │ │ │ ├── requirements.txt
│ │ │ │ └── servers_config.json
│ │ │ └── pyproject.toml
│ │ ├── simple-task-client/
│ │ │ ├── README.md
│ │ │ ├── mcp_simple_task_client/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ └── main.py
│ │ │ └── pyproject.toml
│ │ ├── simple-task-interactive-client/
│ │ │ ├── README.md
│ │ │ ├── mcp_simple_task_interactive_client/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ └── main.py
│ │ │ └── pyproject.toml
│ │ └── sse-polling-client/
│ │ ├── README.md
│ │ ├── mcp_sse_polling_client/
│ │ │ ├── __init__.py
│ │ │ └── main.py
│ │ └── pyproject.toml
│ ├── mcpserver/
│ │ ├── complex_inputs.py
│ │ ├── desktop.py
│ │ ├── direct_call_tool_result_return.py
│ │ ├── echo.py
│ │ ├── icons_demo.py
│ │ ├── logging_and_progress.py
│ │ ├── memory.py
│ │ ├── parameter_descriptions.py
│ │ ├── readme-quickstart.py
│ │ ├── screenshot.py
│ │ ├── simple_echo.py
│ │ ├── text_me.py
│ │ ├── unicode_example.py
│ │ └── weather_structured.py
│ ├── servers/
│ │ ├── everything-server/
│ │ │ ├── README.md
│ │ │ ├── mcp_everything_server/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ └── server.py
│ │ │ └── pyproject.toml
│ │ ├── simple-auth/
│ │ │ ├── README.md
│ │ │ ├── mcp_simple_auth/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ ├── auth_server.py
│ │ │ │ ├── legacy_as_server.py
│ │ │ │ ├── py.typed
│ │ │ │ ├── server.py
│ │ │ │ ├── simple_auth_provider.py
│ │ │ │ └── token_verifier.py
│ │ │ └── pyproject.toml
│ │ ├── simple-pagination/
│ │ │ ├── README.md
│ │ │ ├── mcp_simple_pagination/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ └── server.py
│ │ │ └── pyproject.toml
│ │ ├── simple-prompt/
│ │ │ ├── README.md
│ │ │ ├── mcp_simple_prompt/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ └── server.py
│ │ │ └── pyproject.toml
│ │ ├── simple-resource/
│ │ │ ├── README.md
│ │ │ ├── mcp_simple_resource/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ └── server.py
│ │ │ └── pyproject.toml
│ │ ├── simple-streamablehttp/
│ │ │ ├── README.md
│ │ │ ├── mcp_simple_streamablehttp/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ ├── event_store.py
│ │ │ │ └── server.py
│ │ │ └── pyproject.toml
│ │ ├── simple-streamablehttp-stateless/
│ │ │ ├── README.md
│ │ │ ├── mcp_simple_streamablehttp_stateless/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ └── server.py
│ │ │ └── pyproject.toml
│ │ ├── simple-task/
│ │ │ ├── README.md
│ │ │ ├── mcp_simple_task/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ └── server.py
│ │ │ └── pyproject.toml
│ │ ├── simple-task-interactive/
│ │ │ ├── README.md
│ │ │ ├── mcp_simple_task_interactive/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ └── server.py
│ │ │ └── pyproject.toml
│ │ ├── simple-tool/
│ │ │ ├── README.md
│ │ │ ├── mcp_simple_tool/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ └── server.py
│ │ │ └── pyproject.toml
│ │ ├── sse-polling-demo/
│ │ │ ├── README.md
│ │ │ ├── mcp_sse_polling_demo/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ ├── event_store.py
│ │ │ │ └── server.py
│ │ │ └── pyproject.toml
│ │ └── structured-output-lowlevel/
│ │ ├── mcp_structured_output_lowlevel/
│ │ │ ├── __init__.py
│ │ │ └── __main__.py
│ │ └── pyproject.toml
│ └── snippets/
│ ├── clients/
│ │ ├── __init__.py
│ │ ├── completion_client.py
│ │ ├── display_utilities.py
│ │ ├── oauth_client.py
│ │ ├── pagination_client.py
│ │ ├── parsing_tool_results.py
│ │ ├── stdio_client.py
│ │ ├── streamable_basic.py
│ │ └── url_elicitation_client.py
│ ├── pyproject.toml
│ └── servers/
│ ├── __init__.py
│ ├── basic_prompt.py
│ ├── basic_resource.py
│ ├── basic_tool.py
│ ├── completion.py
│ ├── direct_call_tool_result.py
│ ├── direct_execution.py
│ ├── elicitation.py
│ ├── images.py
│ ├── lifespan_example.py
│ ├── lowlevel/
│ │ ├── __init__.py
│ │ ├── basic.py
│ │ ├── direct_call_tool_result.py
│ │ ├── lifespan.py
│ │ └── structured_output.py
│ ├── mcpserver_quickstart.py
│ ├── notifications.py
│ ├── oauth_server.py
│ ├── pagination_example.py
│ ├── sampling.py
│ ├── streamable_config.py
│ ├── streamable_http_basic_mounting.py
│ ├── streamable_http_host_mounting.py
│ ├── streamable_http_multiple_servers.py
│ ├── streamable_http_path_config.py
│ ├── streamable_starlette_mount.py
│ ├── structured_output.py
│ └── tool_progress.py
├── mkdocs.yml
├── pyproject.toml
├── scripts/
│ ├── test
│ └── update_readme_snippets.py
├── src/
│ └── mcp/
│ ├── __init__.py
│ ├── cli/
│ │ ├── __init__.py
│ │ ├── claude.py
│ │ └── cli.py
│ ├── client/
│ │ ├── __init__.py
│ │ ├── __main__.py
│ │ ├── _memory.py
│ │ ├── _transport.py
│ │ ├── auth/
│ │ │ ├── __init__.py
│ │ │ ├── exceptions.py
│ │ │ ├── extensions/
│ │ │ │ ├── __init__.py
│ │ │ │ └── client_credentials.py
│ │ │ ├── oauth2.py
│ │ │ └── utils.py
│ │ ├── client.py
│ │ ├── context.py
│ │ ├── experimental/
│ │ │ ├── __init__.py
│ │ │ ├── task_handlers.py
│ │ │ └── tasks.py
│ │ ├── session.py
│ │ ├── session_group.py
│ │ ├── sse.py
│ │ ├── stdio.py
│ │ ├── streamable_http.py
│ │ └── websocket.py
│ ├── os/
│ │ ├── __init__.py
│ │ ├── posix/
│ │ │ ├── __init__.py
│ │ │ └── utilities.py
│ │ └── win32/
│ │ ├── __init__.py
│ │ └── utilities.py
│ ├── py.typed
│ ├── server/
│ │ ├── __init__.py
│ │ ├── __main__.py
│ │ ├── auth/
│ │ │ ├── __init__.py
│ │ │ ├── errors.py
│ │ │ ├── handlers/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── authorize.py
│ │ │ │ ├── metadata.py
│ │ │ │ ├── register.py
│ │ │ │ ├── revoke.py
│ │ │ │ └── token.py
│ │ │ ├── json_response.py
│ │ │ ├── middleware/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── auth_context.py
│ │ │ │ ├── bearer_auth.py
│ │ │ │ └── client_auth.py
│ │ │ ├── provider.py
│ │ │ ├── routes.py
│ │ │ └── settings.py
│ │ ├── context.py
│ │ ├── elicitation.py
│ │ ├── experimental/
│ │ │ ├── __init__.py
│ │ │ ├── request_context.py
│ │ │ ├── session_features.py
│ │ │ ├── task_context.py
│ │ │ ├── task_result_handler.py
│ │ │ └── task_support.py
│ │ ├── lowlevel/
│ │ │ ├── __init__.py
│ │ │ ├── experimental.py
│ │ │ ├── helper_types.py
│ │ │ └── server.py
│ │ ├── mcpserver/
│ │ │ ├── __init__.py
│ │ │ ├── context.py
│ │ │ ├── exceptions.py
│ │ │ ├── prompts/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── base.py
│ │ │ │ └── manager.py
│ │ │ ├── resources/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── base.py
│ │ │ │ ├── resource_manager.py
│ │ │ │ ├── templates.py
│ │ │ │ └── types.py
│ │ │ ├── server.py
│ │ │ ├── tools/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── base.py
│ │ │ │ └── tool_manager.py
│ │ │ └── utilities/
│ │ │ ├── __init__.py
│ │ │ ├── context_injection.py
│ │ │ ├── func_metadata.py
│ │ │ ├── logging.py
│ │ │ └── types.py
│ │ ├── models.py
│ │ ├── session.py
│ │ ├── sse.py
│ │ ├── stdio.py
│ │ ├── streamable_http.py
│ │ ├── streamable_http_manager.py
│ │ ├── transport_security.py
│ │ ├── validation.py
│ │ └── websocket.py
│ ├── shared/
│ │ ├── __init__.py
│ │ ├── _context.py
│ │ ├── _httpx_utils.py
│ │ ├── auth.py
│ │ ├── auth_utils.py
│ │ ├── exceptions.py
│ │ ├── experimental/
│ │ │ ├── __init__.py
│ │ │ └── tasks/
│ │ │ ├── __init__.py
│ │ │ ├── capabilities.py
│ │ │ ├── context.py
│ │ │ ├── helpers.py
│ │ │ ├── in_memory_task_store.py
│ │ │ ├── message_queue.py
│ │ │ ├── polling.py
│ │ │ ├── resolver.py
│ │ │ └── store.py
│ │ ├── memory.py
│ │ ├── message.py
│ │ ├── metadata_utils.py
│ │ ├── response_router.py
│ │ ├── session.py
│ │ ├── tool_name_validation.py
│ │ └── version.py
│ └── types/
│ ├── __init__.py
│ ├── _types.py
│ └── jsonrpc.py
└── tests/
├── __init__.py
├── cli/
│ ├── __init__.py
│ ├── test_claude.py
│ └── test_utils.py
├── client/
│ ├── __init__.py
│ ├── auth/
│ │ └── extensions/
│ │ └── test_client_credentials.py
│ ├── conftest.py
│ ├── test_auth.py
│ ├── test_client.py
│ ├── test_http_unicode.py
│ ├── test_list_methods_cursor.py
│ ├── test_list_roots_callback.py
│ ├── test_logging_callback.py
│ ├── test_notification_response.py
│ ├── test_output_schema_validation.py
│ ├── test_resource_cleanup.py
│ ├── test_sampling_callback.py
│ ├── test_scope_bug_1630.py
│ ├── test_session.py
│ ├── test_session_group.py
│ ├── test_stdio.py
│ ├── test_transport_stream_cleanup.py
│ └── transports/
│ ├── __init__.py
│ └── test_memory.py
├── conftest.py
├── experimental/
│ ├── __init__.py
│ └── tasks/
│ ├── __init__.py
│ ├── client/
│ │ ├── __init__.py
│ │ ├── test_capabilities.py
│ │ ├── test_handlers.py
│ │ ├── test_poll_task.py
│ │ └── test_tasks.py
│ ├── server/
│ │ ├── __init__.py
│ │ ├── test_context.py
│ │ ├── test_integration.py
│ │ ├── test_run_task_flow.py
│ │ ├── test_server.py
│ │ ├── test_server_task_context.py
│ │ ├── test_store.py
│ │ └── test_task_result_handler.py
│ ├── test_capabilities.py
│ ├── test_elicitation_scenarios.py
│ ├── test_message_queue.py
│ ├── test_request_context.py
│ └── test_spec_compliance.py
├── issues/
│ ├── test_100_tool_listing.py
│ ├── test_1027_win_unreachable_cleanup.py
│ ├── test_129_resource_templates.py
│ ├── test_1338_icons_and_metadata.py
│ ├── test_1363_race_condition_streamable_http.py
│ ├── test_141_resource_templates.py
│ ├── test_152_resource_mime_type.py
│ ├── test_1574_resource_uri_validation.py
│ ├── test_1754_mime_type_parameters.py
│ ├── test_176_progress_token.py
│ ├── test_188_concurrency.py
│ ├── test_192_request_id.py
│ ├── test_342_base64_encoding.py
│ ├── test_355_type_error.py
│ ├── test_552_windows_hang.py
│ ├── test_88_random_error.py
│ ├── test_973_url_decoding.py
│ └── test_malformed_input.py
├── server/
│ ├── __init__.py
│ ├── auth/
│ │ ├── __init__.py
│ │ ├── middleware/
│ │ │ ├── __init__.py
│ │ │ ├── test_auth_context.py
│ │ │ └── test_bearer_auth.py
│ │ ├── test_error_handling.py
│ │ ├── test_protected_resource.py
│ │ ├── test_provider.py
│ │ └── test_routes.py
│ ├── lowlevel/
│ │ ├── __init__.py
│ │ ├── test_helper_types.py
│ │ ├── test_server_listing.py
│ │ └── test_server_pagination.py
│ ├── mcpserver/
│ │ ├── __init__.py
│ │ ├── auth/
│ │ │ ├── __init__.py
│ │ │ └── test_auth_integration.py
│ │ ├── prompts/
│ │ │ ├── __init__.py
│ │ │ ├── test_base.py
│ │ │ └── test_manager.py
│ │ ├── resources/
│ │ │ ├── __init__.py
│ │ │ ├── test_file_resources.py
│ │ │ ├── test_function_resources.py
│ │ │ ├── test_resource_manager.py
│ │ │ ├── test_resource_template.py
│ │ │ └── test_resources.py
│ │ ├── servers/
│ │ │ ├── __init__.py
│ │ │ └── test_file_server.py
│ │ ├── test_elicitation.py
│ │ ├── test_func_metadata.py
│ │ ├── test_integration.py
│ │ ├── test_parameter_descriptions.py
│ │ ├── test_server.py
│ │ ├── test_title.py
│ │ ├── test_tool_manager.py
│ │ ├── test_url_elicitation.py
│ │ ├── test_url_elicitation_error_throw.py
│ │ └── tools/
│ │ ├── __init__.py
│ │ └── test_base.py
│ ├── test_cancel_handling.py
│ ├── test_completion_with_context.py
│ ├── test_lifespan.py
│ ├── test_lowlevel_exception_handling.py
│ ├── test_lowlevel_tool_annotations.py
│ ├── test_read_resource.py
│ ├── test_session.py
│ ├── test_session_race_condition.py
│ ├── test_sse_security.py
│ ├── test_stateless_mode.py
│ ├── test_stdio.py
│ ├── test_streamable_http_manager.py
│ ├── test_streamable_http_security.py
│ └── test_validation.py
├── shared/
│ ├── __init__.py
│ ├── test_auth.py
│ ├── test_auth_utils.py
│ ├── test_exceptions.py
│ ├── test_httpx_utils.py
│ ├── test_progress_notifications.py
│ ├── test_session.py
│ ├── test_sse.py
│ ├── test_streamable_http.py
│ ├── test_tool_name_validation.py
│ ├── test_win32_utils.py
│ └── test_ws.py
├── test_examples.py
├── test_helpers.py
└── test_types.py
Showing preview only (285K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (2760 symbols across 274 files)
FILE: .github/actions/conformance/client.py
function register (line 60) | def register(name: str) -> Callable[[ScenarioHandler], ScenarioHandler]:
function get_conformance_context (line 70) | def get_conformance_context() -> dict[str, Any]:
class InMemoryTokenStorage (line 84) | class InMemoryTokenStorage(TokenStorage):
method __init__ (line 87) | def __init__(self) -> None:
method get_tokens (line 91) | async def get_tokens(self) -> OAuthToken | None:
method set_tokens (line 94) | async def set_tokens(self, tokens: OAuthToken) -> None:
method get_client_info (line 97) | async def get_client_info(self) -> OAuthClientInformationFull | None:
method set_client_info (line 100) | async def set_client_info(self, client_info: OAuthClientInformationFul...
class ConformanceOAuthCallbackHandler (line 104) | class ConformanceOAuthCallbackHandler:
method __init__ (line 109) | def __init__(self) -> None:
method handle_redirect (line 113) | async def handle_redirect(self, authorization_url: str) -> None:
method handle_callback (line 142) | async def handle_callback(self) -> tuple[str, str | None]:
function run_initialize (line 157) | async def run_initialize(server_url: str) -> None:
function run_tools_call (line 168) | async def run_tools_call(server_url: str) -> None:
function run_sse_retry (line 179) | async def run_sse_retry(server_url: str) -> None:
function default_elicitation_callback (line 189) | async def default_elicitation_callback(
function run_elicitation_defaults (line 210) | async def run_elicitation_defaults(server_url: str) -> None:
function run_client_credentials_jwt (line 223) | async def run_client_credentials_jwt(server_url: str) -> None:
function run_client_credentials_basic (line 253) | async def run_client_credentials_basic(server_url: str) -> None:
function run_auth_code_client (line 275) | async def run_auth_code_client(server_url: str) -> None:
function _run_auth_session (line 317) | async def _run_auth_session(server_url: str, oauth_auth: OAuthClientProv...
function main (line 342) | def main() -> None:
FILE: examples/clients/simple-auth-client/mcp_simple_auth_client/main.py
class InMemoryTokenStorage (line 30) | class InMemoryTokenStorage(TokenStorage):
method __init__ (line 33) | def __init__(self):
method get_tokens (line 37) | async def get_tokens(self) -> OAuthToken | None:
method set_tokens (line 40) | async def set_tokens(self, tokens: OAuthToken) -> None:
method get_client_info (line 43) | async def get_client_info(self) -> OAuthClientInformationFull | None:
method set_client_info (line 46) | async def set_client_info(self, client_info: OAuthClientInformationFul...
class CallbackHandler (line 50) | class CallbackHandler(BaseHTTPRequestHandler):
method __init__ (line 53) | def __init__(
method do_GET (line 64) | def do_GET(self):
method log_message (line 104) | def log_message(self, format: str, *args: Any):
class CallbackServer (line 108) | class CallbackServer:
method __init__ (line 111) | def __init__(self, port: int = 3000):
method _create_handler_with_data (line 117) | def _create_handler_with_data(self):
method start (line 132) | def start(self):
method stop (line 140) | def stop(self):
method wait_for_callback (line 148) | def wait_for_callback(self, timeout: int = 300):
method get_state (line 159) | def get_state(self):
class SimpleAuthClient (line 164) | class SimpleAuthClient:
method __init__ (line 167) | def __init__(
method connect (line 178) | async def connect(self):
method _run_session (line 242) | async def _run_session(
method list_tools (line 260) | async def list_tools(self):
method call_tool (line 280) | async def call_tool(self, tool_name: str, arguments: dict[str, Any] | ...
method interactive_loop (line 300) | async def interactive_loop(self):
function main (line 353) | async def main():
function cli (line 377) | def cli():
FILE: examples/clients/simple-chatbot/mcp_simple_chatbot/main.py
class Configuration (line 20) | class Configuration:
method __init__ (line 23) | def __init__(self) -> None:
method load_env (line 29) | def load_env() -> None:
method load_config (line 34) | def load_config(file_path: str) -> dict[str, Any]:
method llm_api_key (line 51) | def llm_api_key(self) -> str:
class Server (line 65) | class Server:
method __init__ (line 68) | def __init__(self, name: str, config: dict[str, Any]) -> None:
method initialize (line 76) | async def initialize(self) -> None:
method list_tools (line 98) | async def list_tools(self) -> list[Tool]:
method execute_tool (line 119) | async def execute_tool(
method cleanup (line 162) | async def cleanup(self) -> None:
class Tool (line 173) | class Tool:
method __init__ (line 176) | def __init__(
method format_for_llm (line 188) | def format_for_llm(self) -> str:
class LLMClient (line 217) | class LLMClient:
method __init__ (line 220) | def __init__(self, api_key: str) -> None:
method get_response (line 223) | def get_response(self, messages: list[dict[str, str]]) -> str:
class ChatSession (line 270) | class ChatSession:
method __init__ (line 273) | def __init__(self, servers: list[Server], llm_client: LLMClient) -> None:
method cleanup_servers (line 277) | async def cleanup_servers(self) -> None:
method process_llm_response (line 285) | async def process_llm_response(self, llm_response: str) -> str:
method start (line 332) | async def start(self) -> None:
function run (line 406) | async def run() -> None:
function main (line 416) | def main() -> None:
FILE: examples/clients/simple-task-client/mcp_simple_task_client/main.py
function run (line 11) | async def run(url: str) -> None:
function main (line 50) | def main(url: str) -> int:
FILE: examples/clients/simple-task-interactive-client/mcp_simple_task_interactive_client/main.py
function elicitation_callback (line 25) | async def elicitation_callback(
function sampling_callback (line 40) | async def sampling_callback(
function get_text (line 67) | def get_text(result: CallToolResult) -> str:
function run (line 74) | async def run(url: str) -> None:
function main (line 131) | def main(url: str) -> int:
FILE: examples/clients/sse-polling-client/mcp_sse_polling_client/main.py
function run_demo (line 25) | async def run_demo(url: str, items: int, checkpoint_every: int) -> None:
function main (line 88) | def main(url: str, items: int, checkpoint_every: int, log_level: str) ->...
FILE: examples/mcpserver/complex_inputs.py
class ShrimpTank (line 15) | class ShrimpTank(BaseModel):
class Shrimp (line 16) | class Shrimp(BaseModel):
function name_shrimp (line 23) | def name_shrimp(
FILE: examples/mcpserver/desktop.py
function desktop (line 15) | def desktop() -> list[str]:
function sum (line 22) | def sum(a: int, b: int) -> int:
FILE: examples/mcpserver/direct_call_tool_result_return.py
class EchoResponse (line 13) | class EchoResponse(BaseModel):
function echo (line 18) | def echo(text: str) -> Annotated[CallToolResult, EchoResponse]:
FILE: examples/mcpserver/echo.py
function echo_tool (line 10) | def echo_tool(text: str) -> str:
function echo_resource (line 16) | def echo_resource() -> str:
function echo_template (line 21) | def echo_template(text: str) -> str:
function echo_prompt (line 27) | def echo_prompt(text: str) -> str:
FILE: examples/mcpserver/icons_demo.py
function demo_tool (line 25) | def demo_tool(message: str) -> str:
function readme_resource (line 31) | def readme_resource() -> str:
function prompt_with_icon (line 37) | def prompt_with_icon(text: str) -> str:
function multi_icon_tool (line 49) | def multi_icon_tool(action: str) -> str:
FILE: examples/mcpserver/logging_and_progress.py
function echo (line 12) | async def echo(text: str, ctx: Context) -> str:
FILE: examples/mcpserver/memory.py
function cosine_similarity (line 47) | def cosine_similarity(a: list[float], b: list[float]) -> float:
function do_ai (line 53) | async def do_ai(
class Deps (line 69) | class Deps:
function get_db_pool (line 74) | async def get_db_pool() -> asyncpg.Pool:
class MemoryNode (line 83) | class MemoryNode(BaseModel):
method from_content (line 93) | async def from_content(cls, content: str, deps: Deps):
method save (line 97) | async def save(self, deps: Deps):
method merge_with (line 132) | async def merge_with(self, other: Self, deps: Deps):
method get_effective_importance (line 148) | def get_effective_importance(self):
function get_embedding (line 152) | async def get_embedding(text: str, deps: Deps) -> list[float]:
function delete_memory (line 160) | async def delete_memory(memory_id: int, deps: Deps):
function add_memory (line 165) | async def add_memory(content: str, deps: Deps):
function find_similar_memories (line 181) | async def find_similar_memories(embedding: list[float], deps: Deps) -> l...
function update_importance (line 207) | async def update_importance(user_embedding: list[float], deps: Deps):
function prune_memories (line 231) | async def prune_memories(deps: Deps):
function display_memory_tree (line 246) | async def display_memory_tree(deps: Deps) -> str:
function remember (line 266) | async def remember(
function read_profile (line 277) | async def read_profile() -> str:
function initialize_database (line 284) | async def initialize_database():
FILE: examples/mcpserver/parameter_descriptions.py
function greet_user (line 12) | def greet_user(
FILE: examples/mcpserver/readme-quickstart.py
function sum (line 9) | def sum(a: int, b: int) -> int:
function get_greeting (line 16) | def get_greeting(name: str) -> str:
FILE: examples/mcpserver/screenshot.py
function take_screenshot (line 16) | def take_screenshot() -> Image:
FILE: examples/mcpserver/simple_echo.py
function echo (line 10) | def echo(text: str) -> str:
FILE: examples/mcpserver/text_me.py
class SurgeSettings (line 29) | class SurgeSettings(BaseSettings):
function text_me (line 45) | def text_me(text_content: str) -> str:
FILE: examples/mcpserver/unicode_example.py
function hello_unicode (line 11) | def hello_unicode(name: str = "世界", greeting: str = "¡Hola") -> str:
function list_emoji_categories (line 21) | def list_emoji_categories() -> list[str]:
function multilingual_hello (line 37) | def multilingual_hello() -> str:
FILE: examples/mcpserver/weather_structured.py
class WeatherData (line 24) | class WeatherData(BaseModel):
function get_weather (line 36) | def get_weather(city: str) -> WeatherData:
class WeatherSummary (line 43) | class WeatherSummary(TypedDict):
function get_weather_summary (line 52) | def get_weather_summary(city: str) -> WeatherSummary:
function get_weather_metrics (line 59) | def get_weather_metrics(cities: list[str]) -> dict[str, dict[str, float]]:
class WeatherAlert (line 73) | class WeatherAlert:
function get_weather_alerts (line 84) | def get_weather_alerts(region: str) -> list[WeatherAlert]:
function get_temperature (line 109) | def get_temperature(city: str, unit: str = "celsius") -> float:
class DailyStats (line 122) | class DailyStats(BaseModel):
class WeatherStats (line 130) | class WeatherStats(BaseModel):
function get_weather_stats (line 141) | def get_weather_stats(city: str, days: int = 7) -> WeatherStats:
function test (line 154) | async def test() -> None:
function print_schemas (line 196) | async def print_schemas() -> None:
FILE: examples/servers/everything-server/mcp_everything_server/server.py
class InMemoryEventStore (line 44) | class InMemoryEventStore(EventStore):
method __init__ (line 47) | def __init__(self) -> None:
method store_event (line 51) | async def store_event(self, stream_id: StreamId, message: JSONRPCMessa...
method replay_events_after (line 58) | async def replay_events_after(self, last_event_id: EventId, send_callb...
function test_simple_text (line 94) | def test_simple_text() -> str:
function test_image_content (line 100) | def test_image_content() -> list[ImageContent]:
function test_audio_content (line 106) | def test_audio_content() -> list[AudioContent]:
function test_embedded_resource (line 112) | def test_embedded_resource() -> list[EmbeddedResource]:
function test_multiple_content_types (line 127) | def test_multiple_content_types() -> list[TextContent | ImageContent | E...
function test_tool_with_logging (line 144) | async def test_tool_with_logging(ctx: Context) -> str:
function test_tool_with_progress (line 157) | async def test_tool_with_progress(ctx: Context) -> str:
function test_sampling (line 175) | async def test_sampling(prompt: str, ctx: Context) -> str:
class UserResponse (line 195) | class UserResponse(BaseModel):
function test_elicitation (line 200) | async def test_elicitation(message: str, ctx: Context) -> str:
class SEP1034DefaultsSchema (line 217) | class SEP1034DefaultsSchema(BaseModel):
function test_elicitation_sep1034_defaults (line 232) | async def test_elicitation_sep1034_defaults(ctx: Context) -> str:
class EnumSchemasTestSchema (line 249) | class EnumSchemasTestSchema(BaseModel):
function test_elicitation_sep1330_enums (line 291) | async def test_elicitation_sep1330_enums(ctx: Context) -> str:
function test_error_handling (line 309) | def test_error_handling() -> str:
function test_reconnection (line 315) | async def test_reconnection(ctx: Context) -> str:
function static_text_resource (line 329) | def static_text_resource() -> str:
function static_binary_resource (line 335) | def static_binary_resource() -> bytes:
function template_resource (line 341) | def template_resource(id: str) -> str:
function watched_resource (line 347) | def watched_resource() -> str:
function test_simple_prompt (line 354) | def test_simple_prompt() -> list[UserMessage]:
function test_prompt_with_arguments (line 360) | def test_prompt_with_arguments(arg1: str, arg2: str) -> list[UserMessage]:
function test_prompt_with_embedded_resource (line 370) | def test_prompt_with_embedded_resource(resourceUri: str) -> list[UserMes...
function test_prompt_with_image (line 389) | def test_prompt_with_image() -> list[UserMessage]:
function handle_set_logging_level (line 400) | async def handle_set_logging_level(ctx: ServerRequestContext, params: Se...
function handle_subscribe (line 406) | async def handle_subscribe(ctx: ServerRequestContext, params: SubscribeR...
function handle_unsubscribe (line 413) | async def handle_unsubscribe(ctx: ServerRequestContext, params: Unsubscr...
function _handle_completion (line 426) | async def _handle_completion(
function main (line 445) | def main(port: int, log_level: str) -> int:
FILE: examples/servers/simple-auth/mcp_simple_auth/auth_server.py
class AuthServerSettings (line 32) | class AuthServerSettings(BaseModel):
class SimpleAuthProvider (line 42) | class SimpleAuthProvider(SimpleOAuthProvider):
method __init__ (line 50) | def __init__(self, auth_settings: SimpleAuthSettings, auth_callback_pa...
function create_authorization_server (line 54) | def create_authorization_server(server_settings: AuthServerSettings, aut...
function run_server (line 137) | async def run_server(server_settings: AuthServerSettings, auth_settings:...
function main (line 156) | def main(port: int) -> int:
FILE: examples/servers/simple-auth/mcp_simple_auth/legacy_as_server.py
class ServerSettings (line 29) | class ServerSettings(BaseModel):
class LegacySimpleOAuthProvider (line 39) | class LegacySimpleOAuthProvider(SimpleOAuthProvider):
method __init__ (line 42) | def __init__(self, auth_settings: SimpleAuthSettings, auth_callback_pa...
function create_simple_mcp_server (line 46) | def create_simple_mcp_server(server_settings: ServerSettings, auth_setti...
function main (line 115) | def main(port: int, transport: Literal["sse", "streamable-http"]) -> int:
FILE: examples/servers/simple-auth/mcp_simple_auth/server.py
class ResourceServerSettings (line 26) | class ResourceServerSettings(BaseSettings):
function create_resource_server (line 48) | def create_resource_server(settings: ResourceServerSettings) -> MCPServer:
function main (line 113) | def main(port: int, auth_server: str, transport: Literal["sse", "streama...
FILE: examples/servers/simple-auth/mcp_simple_auth/simple_auth_provider.py
class SimpleAuthSettings (line 32) | class SimpleAuthSettings(BaseSettings):
class SimpleOAuthProvider (line 45) | class SimpleOAuthProvider(OAuthAuthorizationServerProvider[Authorization...
method __init__ (line 54) | def __init__(self, settings: SimpleAuthSettings, auth_callback_url: st...
method get_client (line 65) | async def get_client(self, client_id: str) -> OAuthClientInformationFu...
method register_client (line 69) | async def register_client(self, client_info: OAuthClientInformationFull):
method authorize (line 75) | async def authorize(self, client: OAuthClientInformationFull, params: ...
method get_login_page (line 93) | async def get_login_page(self, state: str) -> HTMLResponse:
method handle_login_callback (line 135) | async def handle_login_callback(self, request: Request) -> Response:
method handle_simple_callback (line 152) | async def handle_simple_callback(self, username: str, password: str, s...
method load_authorization_code (line 197) | async def load_authorization_code(
method exchange_authorization_code (line 203) | async def exchange_authorization_code(
method load_access_token (line 240) | async def load_access_token(self, token: str) -> AccessToken | None:
method load_refresh_token (line 253) | async def load_refresh_token(self, client: OAuthClientInformationFull,...
method exchange_refresh_token (line 257) | async def exchange_refresh_token(
method revoke_token (line 267) | async def revoke_token(self, token: str, token_type_hint: str | None =...
FILE: examples/servers/simple-auth/mcp_simple_auth/token_verifier.py
class IntrospectionTokenVerifier (line 12) | class IntrospectionTokenVerifier(TokenVerifier):
method __init__ (line 23) | def __init__(
method verify_token (line 34) | async def verify_token(self, token: str) -> AccessToken | None:
method _validate_resource (line 83) | def _validate_resource(self, token_data: dict[str, Any]) -> bool:
method _is_valid_resource (line 101) | def _is_valid_resource(self, resource: str) -> bool:
FILE: examples/servers/simple-pagination/mcp_simple_pagination/server.py
function _paginate (line 48) | def _paginate(cursor: str | None, items: list[T], page_size: int) -> tup...
function handle_list_tools (line 64) | async def handle_list_tools(
function handle_list_resources (line 73) | async def handle_list_resources(
function handle_list_prompts (line 82) | async def handle_list_prompts(
function handle_call_tool (line 90) | async def handle_call_tool(ctx: ServerRequestContext, params: types.Call...
function handle_read_resource (line 106) | async def handle_read_resource(
function handle_get_prompt (line 124) | async def handle_get_prompt(ctx: ServerRequestContext, params: types.Get...
function main (line 152) | def main(port: int, transport: str) -> int:
FILE: examples/servers/simple-prompt/mcp_simple_prompt/server.py
function create_messages (line 7) | def create_messages(context: str | None = None, topic: str | None = None...
function handle_list_prompts (line 32) | async def handle_list_prompts(
function handle_get_prompt (line 58) | async def handle_get_prompt(ctx: ServerRequestContext, params: types.Get...
function main (line 78) | def main(port: int, transport: str) -> int:
FILE: examples/servers/simple-resource/mcp_simple_resource/server.py
function handle_list_resources (line 24) | async def handle_list_resources(
function handle_read_resource (line 41) | async def handle_read_resource(
function main (line 71) | def main(port: int, transport: str) -> int:
FILE: examples/servers/simple-streamablehttp-stateless/mcp_simple_streamablehttp_stateless/server.py
function handle_list_tools (line 13) | async def handle_list_tools(
function handle_call_tool (line 44) | async def handle_call_tool(ctx: ServerRequestContext, params: types.Call...
function main (line 84) | def main(
FILE: examples/servers/simple-streamablehttp/mcp_simple_streamablehttp/event_store.py
class EventEntry (line 19) | class EventEntry:
class InMemoryEventStore (line 27) | class InMemoryEventStore(EventStore):
method __init__ (line 35) | def __init__(self, max_events_per_stream: int = 100):
method store_event (line 47) | async def store_event(self, stream_id: StreamId, message: JSONRPCMessa...
method replay_events_after (line 68) | async def replay_events_after(
FILE: examples/servers/simple-streamablehttp/mcp_simple_streamablehttp/server.py
function handle_list_tools (line 16) | async def handle_list_tools(
function handle_call_tool (line 47) | async def handle_call_tool(ctx: ServerRequestContext, params: types.Call...
function main (line 98) | def main(
FILE: examples/servers/simple-task-interactive/mcp_simple_task_interactive/server.py
function handle_list_tools (line 18) | async def handle_list_tools(
function handle_confirm_delete (line 42) | async def handle_confirm_delete(ctx: ServerRequestContext, arguments: di...
function handle_write_haiku (line 75) | async def handle_write_haiku(ctx: ServerRequestContext, arguments: dict[...
function handle_call_tool (line 105) | async def handle_call_tool(
function main (line 134) | def main(port: int) -> int:
FILE: examples/servers/simple-task/mcp_simple_task/server.py
function handle_list_tools (line 11) | async def handle_list_tools(
function handle_call_tool (line 26) | async def handle_call_tool(
function main (line 65) | def main(port: int) -> int:
FILE: examples/servers/simple-tool/mcp_simple_tool/server.py
function fetch_website (line 8) | async def fetch_website(
function handle_list_tools (line 18) | async def handle_list_tools(
function handle_call_tool (line 42) | async def handle_call_tool(ctx: ServerRequestContext, params: types.Call...
function main (line 60) | def main(port: int, transport: str) -> int:
FILE: examples/servers/sse-polling-demo/mcp_sse_polling_demo/event_store.py
class EventEntry (line 19) | class EventEntry:
class InMemoryEventStore (line 27) | class InMemoryEventStore(EventStore):
method __init__ (line 35) | def __init__(self, max_events_per_stream: int = 100):
method store_event (line 47) | async def store_event(self, stream_id: StreamId, message: JSONRPCMessa...
method replay_events_after (line 73) | async def replay_events_after(
FILE: examples/servers/sse-polling-demo/mcp_sse_polling_demo/server.py
function handle_list_tools (line 28) | async def handle_list_tools(
function handle_call_tool (line 60) | async def handle_call_tool(ctx: ServerRequestContext, params: types.Call...
function main (line 134) | def main(port: int, log_level: str, retry_interval: int) -> int:
FILE: examples/servers/structured-output-lowlevel/mcp_structured_output_lowlevel/__main__.py
function handle_list_tools (line 18) | async def handle_list_tools(
function handle_call_tool (line 48) | async def handle_call_tool(ctx: ServerRequestContext, params: types.Call...
function run (line 78) | async def run():
FILE: examples/snippets/clients/completion_client.py
function run (line 20) | async def run():
function main (line 71) | def main():
FILE: examples/snippets/clients/display_utilities.py
function display_tools (line 20) | async def display_tools(session: ClientSession):
function display_resources (line 32) | async def display_resources(session: ClientSession):
function run (line 46) | async def run():
function main (line 60) | def main():
FILE: examples/snippets/clients/oauth_client.py
class InMemoryTokenStorage (line 21) | class InMemoryTokenStorage(TokenStorage):
method __init__ (line 24) | def __init__(self):
method get_tokens (line 28) | async def get_tokens(self) -> OAuthToken | None:
method set_tokens (line 32) | async def set_tokens(self, tokens: OAuthToken) -> None:
method get_client_info (line 36) | async def get_client_info(self) -> OAuthClientInformationFull | None:
method set_client_info (line 40) | async def set_client_info(self, client_info: OAuthClientInformationFul...
function handle_redirect (line 45) | async def handle_redirect(auth_url: str) -> None:
function handle_callback (line 49) | async def handle_callback() -> tuple[str, str | None]:
function main (line 55) | async def main():
function run (line 83) | def run():
FILE: examples/snippets/clients/pagination_client.py
function list_all_resources (line 10) | async def list_all_resources() -> None:
FILE: examples/snippets/clients/parsing_tool_results.py
function parse_tool_results (line 9) | async def parse_tool_results():
function main (line 55) | async def main():
FILE: examples/snippets/clients/stdio_client.py
function handle_sampling_message (line 21) | async def handle_sampling_message(
function run (line 36) | async def run():
function main (line 74) | def main():
FILE: examples/snippets/clients/streamable_basic.py
function main (line 11) | async def main():
FILE: examples/snippets/clients/url_elicitation_client.py
function handle_elicitation (line 38) | async def handle_elicitation(
function handle_url_elicitation (line 60) | async def handle_url_elicitation(
function extract_domain (line 128) | def extract_domain(url: str) -> str:
function call_tool_with_error_handling (line 136) | async def call_tool_with_error_handling(
function print_help (line 180) | def print_help() -> None:
function print_tool_result (line 191) | def print_tool_result(result: types.CallToolResult | None) -> None:
function handle_list_tools (line 203) | async def handle_list_tools(session: ClientSession) -> None:
function handle_call_command (line 214) | async def handle_call_command(session: ClientSession, command: str) -> N...
function process_command (line 235) | async def process_command(session: ClientSession, command: str) -> bool:
function run_command_loop (line 262) | async def run_command_loop(session: ClientSession) -> None:
function main (line 280) | async def main() -> None:
function run (line 310) | def run() -> None:
FILE: examples/snippets/servers/__init__.py
function run_server (line 15) | def run_server():
FILE: examples/snippets/servers/basic_prompt.py
function review_code (line 8) | def review_code(code: str) -> str:
function debug_error (line 13) | def debug_error(error: str) -> list[base.Message]:
FILE: examples/snippets/servers/basic_resource.py
function read_document (line 7) | def read_document(name: str) -> str:
function get_settings (line 14) | def get_settings() -> str:
FILE: examples/snippets/servers/basic_tool.py
function sum (line 7) | def sum(a: int, b: int) -> int:
function get_weather (line 13) | def get_weather(city: str, unit: str = "celsius") -> str:
FILE: examples/snippets/servers/completion.py
function github_repo (line 14) | def github_repo(owner: str, repo: str) -> str:
function review_code (line 20) | def review_code(language: str, code: str) -> str:
function handle_completion (line 26) | async def handle_completion(
FILE: examples/snippets/servers/direct_call_tool_result.py
class ValidationModel (line 13) | class ValidationModel(BaseModel):
function advanced_tool (line 21) | def advanced_tool() -> CallToolResult:
function validated_tool (line 30) | def validated_tool() -> Annotated[CallToolResult, ValidationModel]:
function empty_result_tool (line 40) | def empty_result_tool() -> CallToolResult:
FILE: examples/snippets/servers/direct_execution.py
function hello (line 16) | def hello(name: str = "World") -> str:
function main (line 21) | def main():
FILE: examples/snippets/servers/elicitation.py
class BookingPreferences (line 19) | class BookingPreferences(BaseModel):
function book_table (line 30) | async def book_table(date: str, time: str, party_size: int, ctx: Context...
function secure_payment (line 54) | async def secure_payment(amount: float, ctx: Context) -> str:
function connect_service (line 78) | async def connect_service(service_name: str, ctx: Context) -> str:
FILE: examples/snippets/servers/images.py
function create_thumbnail (line 11) | def create_thumbnail(image_path: str) -> Image:
FILE: examples/snippets/servers/lifespan_example.py
class Database (line 11) | class Database:
method connect (line 15) | async def connect(cls) -> "Database":
method disconnect (line 19) | async def disconnect(self) -> None:
method query (line 23) | def query(self) -> str:
class AppContext (line 29) | class AppContext:
function app_lifespan (line 36) | async def app_lifespan(server: MCPServer) -> AsyncIterator[AppContext]:
function query_db (line 53) | def query_db(ctx: Context[AppContext]) -> str:
FILE: examples/snippets/servers/lowlevel/basic.py
function handle_list_prompts (line 12) | async def handle_list_prompts(
function handle_get_prompt (line 27) | async def handle_get_prompt(ctx: ServerRequestContext, params: types.Get...
function run (line 52) | async def run():
FILE: examples/snippets/servers/lowlevel/direct_call_tool_result.py
function handle_list_tools (line 12) | async def handle_list_tools(
function handle_call_tool (line 31) | async def handle_call_tool(ctx: ServerRequestContext, params: types.Call...
function run (line 51) | async def run():
FILE: examples/snippets/servers/lowlevel/lifespan.py
class Database (line 15) | class Database:
method connect (line 19) | async def connect(cls) -> "Database":
method disconnect (line 24) | async def disconnect(self) -> None:
method query (line 28) | async def query(self, query_str: str) -> list[dict[str, str]]:
class AppContext (line 34) | class AppContext(TypedDict):
function server_lifespan (line 39) | async def server_lifespan(_server: Server[AppContext]) -> AsyncIterator[...
function handle_list_tools (line 48) | async def handle_list_tools(
function handle_call_tool (line 67) | async def handle_call_tool(
function run (line 88) | async def run():
FILE: examples/snippets/servers/lowlevel/structured_output.py
function handle_list_tools (line 13) | async def handle_list_tools(
function handle_call_tool (line 42) | async def handle_call_tool(ctx: ServerRequestContext, params: types.Call...
function run (line 69) | async def run():
FILE: examples/snippets/servers/mcpserver_quickstart.py
function add (line 15) | def add(a: int, b: int) -> int:
function get_greeting (line 22) | def get_greeting(name: str) -> str:
function greet_user (line 29) | def greet_user(name: str, style: str = "friendly") -> str:
FILE: examples/snippets/servers/notifications.py
function process_data (line 7) | async def process_data(data: str, ctx: Context) -> str:
FILE: examples/snippets/servers/oauth_server.py
class SimpleTokenVerifier (line 12) | class SimpleTokenVerifier(TokenVerifier):
method verify_token (line 15) | async def verify_token(self, token: str) -> AccessToken | None:
function get_weather (line 34) | async def get_weather(city: str = "London") -> dict[str, str]:
FILE: examples/snippets/servers/pagination_example.py
function handle_list_resources (line 10) | async def handle_list_resources(
FILE: examples/snippets/servers/sampling.py
function generate_poem (line 8) | async def generate_poem(topic: str, ctx: Context) -> str:
FILE: examples/snippets/servers/streamable_config.py
function greet (line 12) | def greet(name: str = "World") -> str:
FILE: examples/snippets/servers/streamable_http_basic_mounting.py
function hello (line 19) | def hello() -> str:
function lifespan (line 26) | async def lifespan(app: Starlette):
FILE: examples/snippets/servers/streamable_http_host_mounting.py
function domain_info (line 19) | def domain_info() -> str:
function lifespan (line 26) | async def lifespan(app: Starlette):
FILE: examples/snippets/servers/streamable_http_multiple_servers.py
function api_status (line 20) | def api_status() -> str:
function send_message (line 26) | def send_message(message: str) -> str:
function lifespan (line 33) | async def lifespan(app: Starlette):
FILE: examples/snippets/servers/streamable_http_path_config.py
function process_data (line 17) | def process_data(data: str) -> str:
FILE: examples/snippets/servers/streamable_starlette_mount.py
function echo (line 17) | def echo(message: str) -> str:
function add_two (line 27) | def add_two(n: int) -> int:
function lifespan (line 34) | async def lifespan(app: Starlette):
FILE: examples/snippets/servers/structured_output.py
class WeatherData (line 13) | class WeatherData(BaseModel):
function get_weather (line 23) | def get_weather(city: str) -> WeatherData:
class LocationInfo (line 35) | class LocationInfo(TypedDict):
function get_location (line 42) | def get_location(address: str) -> LocationInfo:
function get_statistics (line 49) | def get_statistics(data_type: str) -> dict[str, float]:
class UserProfile (line 55) | class UserProfile:
method __init__ (line 60) | def __init__(self, name: str, age: int, email: str | None = None):
function get_user (line 67) | def get_user(user_id: str) -> UserProfile:
class UntypedConfig (line 73) | class UntypedConfig:
method __init__ (line 74) | def __init__(self, setting1, setting2): # type: ignore[reportMissingP...
function get_config (line 80) | def get_config() -> UntypedConfig:
function list_cities (line 87) | def list_cities() -> list[str]:
function get_temperature (line 94) | def get_temperature(city: str) -> float:
FILE: examples/snippets/servers/tool_progress.py
function long_running_task (line 7) | async def long_running_task(task_name: str, ctx: Context, steps: int = 5...
FILE: scripts/update_readme_snippets.py
function get_github_url (line 18) | def get_github_url(file_path: str) -> str:
function process_snippet_block (line 31) | def process_snippet_block(match: re.Match[str], check_mode: bool = False...
function update_readme_snippets (line 94) | def update_readme_snippets(readme_path: Path = Path("README.md"), check_...
function main (line 141) | def main():
FILE: src/mcp/cli/claude.py
function get_claude_config_path (line 17) | def get_claude_config_path() -> Path | None: # pragma: no cover
function get_uv_path (line 33) | def get_uv_path() -> str:
function update_claude_config (line 44) | def update_claude_config(
FILE: src/mcp/cli/cli.py
function _get_npx_command (line 42) | def _get_npx_command():
function _parse_env_var (line 56) | def _parse_env_var(env_var: str) -> tuple[str, str]: # pragma: no cover
function _build_uv_command (line 65) | def _build_uv_command(
function _parse_file_path (line 88) | def _parse_file_path(file_spec: str) -> tuple[Path, str | None]:
function _import_server (line 119) | def _import_server(file: Path, server_object: str | None = None): # pra...
function version (line 210) | def version() -> None: # pragma: no cover
function dev (line 221) | def dev(
function run (line 304) | def run(
function install (line 361) | def install(
FILE: src/mcp/client/__main__.py
function message_handler (line 25) | async def message_handler(
function run_session (line 35) | async def run_session(
function main (line 51) | async def main(command_or_url: str, args: list[str], env: list[tuple[str...
function cli (line 65) | def cli():
FILE: src/mcp/client/_memory.py
class InMemoryTransport (line 18) | class InMemoryTransport:
method __init__ (line 26) | def __init__(self, server: Server[Any] | MCPServer, *, raise_exception...
method _connect (line 38) | async def _connect(self) -> AsyncIterator[TransportStreams]:
method __aenter__ (line 67) | async def __aenter__(self) -> TransportStreams:
method __aexit__ (line 72) | async def __aexit__(
FILE: src/mcp/client/_transport.py
class Transport (line 15) | class Transport(AbstractAsyncContextManager[TransportStreams], Protocol):
FILE: src/mcp/client/auth/exceptions.py
class OAuthFlowError (line 1) | class OAuthFlowError(Exception):
class OAuthTokenError (line 5) | class OAuthTokenError(OAuthFlowError):
class OAuthRegistrationError (line 9) | class OAuthRegistrationError(OAuthFlowError):
FILE: src/mcp/client/auth/extensions/client_credentials.py
class ClientCredentialsOAuthProvider (line 24) | class ClientCredentialsOAuthProvider(OAuthClientProvider):
method __init__ (line 41) | def __init__(
method _initialize (line 79) | async def _initialize(self) -> None:
method _perform_authorization (line 85) | async def _perform_authorization(self) -> httpx.Request:
method _exchange_token_client_credentials (line 89) | async def _exchange_token_client_credentials(self) -> httpx.Request:
function static_assertion_provider (line 110) | def static_assertion_provider(token: str) -> Callable[[str], Awaitable[s...
class SignedJWTParameters (line 139) | class SignedJWTParameters(BaseModel):
method create_assertion_provider (line 168) | def create_assertion_provider(self) -> Callable[[str], Awaitable[str]]:
class PrivateKeyJWTOAuthProvider (line 194) | class PrivateKeyJWTOAuthProvider(OAuthClientProvider):
method __init__ (line 254) | def __init__(
method _initialize (line 293) | async def _initialize(self) -> None:
method _perform_authorization (line 299) | async def _perform_authorization(self) -> httpx.Request:
method _add_client_authentication_jwt (line 303) | async def _add_client_authentication_jwt(self, *, token_data: dict[str...
method _exchange_token_client_credentials (line 317) | async def _exchange_token_client_credentials(self) -> httpx.Request:
class JWTParameters (line 338) | class JWTParameters(BaseModel):
method to_assertion (line 355) | def to_assertion(self, with_audience_fallback: str | None = None) -> str:
class RFC7523OAuthClientProvider (line 390) | class RFC7523OAuthClientProvider(OAuthClientProvider):
method __init__ (line 402) | def __init__(
method _exchange_token_authorization_code (line 421) | async def _exchange_token_authorization_code(
method _perform_authorization (line 430) | async def _perform_authorization(self) -> httpx.Request: # pragma: no...
method _add_client_authentication_jwt (line 438) | def _add_client_authentication_jwt(self, *, token_data: dict[str, Any]...
method _exchange_token_jwt_bearer (line 457) | async def _exchange_token_jwt_bearer(self) -> httpx.Request:
FILE: src/mcp/client/auth/oauth2.py
class PKCEParameters (line 56) | class PKCEParameters(BaseModel):
method generate (line 63) | def generate(cls) -> "PKCEParameters":
class TokenStorage (line 71) | class TokenStorage(Protocol):
method get_tokens (line 74) | async def get_tokens(self) -> OAuthToken | None:
method set_tokens (line 78) | async def set_tokens(self, tokens: OAuthToken) -> None:
method get_client_info (line 82) | async def get_client_info(self) -> OAuthClientInformationFull | None:
method set_client_info (line 86) | async def set_client_info(self, client_info: OAuthClientInformationFul...
class OAuthContext (line 92) | class OAuthContext:
method get_authorization_base_url (line 119) | def get_authorization_base_url(self, server_url: str) -> str:
method update_token_expiry (line 124) | def update_token_expiry(self, token: OAuthToken) -> None:
method is_token_valid (line 128) | def is_token_valid(self) -> bool:
method can_refresh_token (line 136) | def can_refresh_token(self) -> bool:
method clear_tokens (line 140) | def clear_tokens(self) -> None:
method get_resource_url (line 145) | def get_resource_url(self) -> str:
method should_include_resource_param (line 160) | def should_include_resource_param(self, protocol_version: str | None =...
method prepare_token_auth (line 179) | def prepare_token_auth(
class OAuthClientProvider (line 217) | class OAuthClientProvider(httpx.Auth):
method __init__ (line 225) | def __init__(
method _handle_protected_resource_response (line 276) | async def _handle_protected_resource_response(self, response: httpx.Re...
method _perform_authorization (line 307) | async def _perform_authorization(self) -> httpx.Request:
method _perform_authorization_code_grant (line 313) | async def _perform_authorization_code_grant(self) -> tuple[str, str]:
method _get_token_endpoint (line 366) | def _get_token_endpoint(self) -> str:
method _exchange_token_authorization_code (line 374) | async def _exchange_token_authorization_code(
method _handle_token_response (line 405) | async def _handle_token_response(self, response: httpx.Response) -> None:
method _refresh_token (line 420) | async def _refresh_token(self) -> httpx.Request:
method _handle_refresh_response (line 450) | async def _handle_refresh_response(self, response: httpx.Response) -> ...
method _initialize (line 471) | async def _initialize(self) -> None: # pragma: no cover
method _add_auth_header (line 477) | def _add_auth_header(self, request: httpx.Request) -> None:
method _handle_oauth_metadata_response (line 482) | async def _handle_oauth_metadata_response(self, response: httpx.Respon...
method _validate_resource_match (line 487) | async def _validate_resource_match(self, prm: ProtectedResourceMetadat...
method async_auth_flow (line 501) | async def async_auth_flow(self, request: httpx.Request) -> AsyncGenera...
FILE: src/mcp/client/auth/utils.py
function extract_field_from_www_auth (line 19) | def extract_field_from_www_auth(response: Response, field_name: str) -> ...
function extract_scope_from_www_auth (line 40) | def extract_scope_from_www_auth(response: Response) -> str | None:
function extract_resource_metadata_from_www_auth (line 49) | def extract_resource_metadata_from_www_auth(response: Response) -> str |...
function build_protected_resource_metadata_discovery_urls (line 61) | def build_protected_resource_metadata_discovery_urls(www_auth_url: str |...
function get_client_metadata_scopes (line 98) | def get_client_metadata_scopes(
function build_oauth_authorization_server_metadata_discovery_urls (line 122) | def build_oauth_authorization_server_metadata_discovery_urls(auth_server...
function handle_protected_resource_response (line 165) | async def handle_protected_resource_response(
function handle_auth_metadata_response (line 189) | async def handle_auth_metadata_response(response: Response) -> tuple[boo...
function create_oauth_metadata_request (line 202) | def create_oauth_metadata_request(url: str) -> Request:
function create_client_registration_request (line 206) | def create_client_registration_request(
function handle_registration_response (line 221) | async def handle_registration_response(response: Response) -> OAuthClien...
function is_valid_client_metadata_url (line 237) | def is_valid_client_metadata_url(url: str | None) -> bool:
function should_use_client_metadata_url (line 257) | def should_use_client_metadata_url(
function create_client_info_from_metadata_url (line 283) | def create_client_info_from_metadata_url(
function handle_token_response_scopes (line 306) | async def handle_token_response_scopes(
FILE: src/mcp/client/client.py
class Client (line 37) | class Client:
method __post_init__ (line 102) | def __post_init__(self) -> None:
method __aenter__ (line 110) | async def __aenter__(self) -> Client:
method __aexit__ (line 138) | async def __aexit__(self, exc_type: type[BaseException] | None, exc_va...
method session (line 145) | def session(self) -> ClientSession:
method initialize_result (line 158) | def initialize_result(self) -> InitializeResult:
method send_ping (line 169) | async def send_ping(self, *, meta: RequestParamsMeta | None = None) ->...
method send_progress_notification (line 173) | async def send_progress_notification(
method set_logging_level (line 188) | async def set_logging_level(self, level: LoggingLevel, *, meta: Reques...
method list_resources (line 192) | async def list_resources(
method list_resource_templates (line 201) | async def list_resource_templates(
method read_resource (line 210) | async def read_resource(self, uri: str, *, meta: RequestParamsMeta | N...
method subscribe_resource (line 222) | async def subscribe_resource(self, uri: str, *, meta: RequestParamsMet...
method unsubscribe_resource (line 226) | async def unsubscribe_resource(self, uri: str, *, meta: RequestParamsM...
method call_tool (line 230) | async def call_tool(
method list_prompts (line 259) | async def list_prompts(
method get_prompt (line 268) | async def get_prompt(
method complete (line 283) | async def complete(
method list_tools (line 301) | async def list_tools(self, *, cursor: str | None = None, meta: Request...
method send_roots_list_changed (line 305) | async def send_roots_list_changed(self) -> None:
FILE: src/mcp/client/experimental/task_handlers.py
class GetTaskHandlerFnT (line 29) | class GetTaskHandlerFnT(Protocol):
method __call__ (line 35) | async def __call__(
class GetTaskResultHandlerFnT (line 42) | class GetTaskResultHandlerFnT(Protocol):
method __call__ (line 48) | async def __call__(
class ListTasksHandlerFnT (line 55) | class ListTasksHandlerFnT(Protocol):
method __call__ (line 61) | async def __call__(
class CancelTaskHandlerFnT (line 68) | class CancelTaskHandlerFnT(Protocol):
method __call__ (line 74) | async def __call__(
class TaskAugmentedSamplingFnT (line 81) | class TaskAugmentedSamplingFnT(Protocol):
method __call__ (line 91) | async def __call__(
class TaskAugmentedElicitationFnT (line 99) | class TaskAugmentedElicitationFnT(Protocol):
method __call__ (line 109) | async def __call__(
function default_get_task_handler (line 117) | async def default_get_task_handler(
function default_get_task_result_handler (line 127) | async def default_get_task_result_handler(
function default_list_tasks_handler (line 137) | async def default_list_tasks_handler(
function default_cancel_task_handler (line 147) | async def default_cancel_task_handler(
function default_task_augmented_sampling (line 157) | async def default_task_augmented_sampling(
function default_task_augmented_elicitation (line 168) | async def default_task_augmented_elicitation(
class ExperimentalTaskHandlers (line 180) | class ExperimentalTaskHandlers:
method build_capability (line 209) | def build_capability(self) -> types.ClientTasksCapability | None:
method handles_request (line 246) | def handles_request(request: types.ServerRequest) -> bool:
method handle_request (line 253) | async def handle_request(
FILE: src/mcp/client/experimental/tasks.py
class ExperimentalClientFeatures (line 41) | class ExperimentalClientFeatures:
method __init__ (line 50) | def __init__(self, session: "ClientSession") -> None:
method call_tool_as_task (line 53) | async def call_tool_as_task(
method get_task (line 107) | async def get_task(self, task_id: str) -> types.GetTaskResult:
method get_task_result (line 121) | async def get_task_result(
method list_tasks (line 146) | async def list_tasks(
method cancel_task (line 164) | async def cancel_task(self, task_id: str) -> types.CancelTaskResult:
method poll_task (line 180) | async def poll_task(self, task_id: str) -> AsyncIterator[types.GetTask...
FILE: src/mcp/client/session.py
class SamplingFnT (line 24) | class SamplingFnT(Protocol):
method __call__ (line 25) | async def __call__(
class ElicitationFnT (line 32) | class ElicitationFnT(Protocol):
method __call__ (line 33) | async def __call__(
class ListRootsFnT (line 40) | class ListRootsFnT(Protocol):
method __call__ (line 41) | async def __call__(
class LoggingFnT (line 46) | class LoggingFnT(Protocol):
method __call__ (line 47) | async def __call__(self, params: types.LoggingMessageNotificationParam...
class MessageHandlerFnT (line 50) | class MessageHandlerFnT(Protocol):
method __call__ (line 51) | async def __call__(
function _default_message_handler (line 57) | async def _default_message_handler(
function _default_sampling_callback (line 63) | async def _default_sampling_callback(
function _default_elicitation_callback (line 73) | async def _default_elicitation_callback(
function _default_list_roots_callback (line 83) | async def _default_list_roots_callback(
function _default_logging_callback (line 92) | async def _default_logging_callback(
class ClientSession (line 101) | class ClientSession(
method __init__ (line 110) | def __init__(
method _receive_request_adapter (line 141) | def _receive_request_adapter(self) -> TypeAdapter[types.ServerRequest]:
method _receive_notification_adapter (line 145) | def _receive_notification_adapter(self) -> TypeAdapter[types.ServerNot...
method initialize (line 148) | async def initialize(self) -> types.InitializeResult:
method initialize_result (line 195) | def initialize_result(self) -> types.InitializeResult | None:
method experimental (line 203) | def experimental(self) -> ExperimentalClientFeatures:
method send_ping (line 219) | async def send_ping(self, *, meta: RequestParamsMeta | None = None) ->...
method send_progress_notification (line 223) | async def send_progress_notification(
method set_logging_level (line 245) | async def set_logging_level(
method list_resources (line 257) | async def list_resources(self, *, params: types.PaginatedRequestParams...
method list_resource_templates (line 265) | async def list_resource_templates(
method read_resource (line 278) | async def read_resource(self, uri: str, *, meta: RequestParamsMeta | N...
method subscribe_resource (line 285) | async def subscribe_resource(self, uri: str, *, meta: RequestParamsMet...
method unsubscribe_resource (line 292) | async def unsubscribe_resource(self, uri: str, *, meta: RequestParamsM...
method call_tool (line 299) | async def call_tool(
method _validate_tool_result (line 324) | async def _validate_tool_result(self, name: str, result: types.CallToo...
method list_prompts (line 350) | async def list_prompts(self, *, params: types.PaginatedRequestParams |...
method get_prompt (line 358) | async def get_prompt(
method complete (line 371) | async def complete(
method list_tools (line 393) | async def list_tools(self, *, params: types.PaginatedRequestParams | N...
method send_roots_list_changed (line 411) | async def send_roots_list_changed(self) -> None: # pragma: no cover
method _received_request (line 415) | async def _received_request(self, responder: RequestResponder[types.Se...
method _handle_incoming (line 461) | async def _handle_incoming(
method _received_notification (line 468) | async def _received_notification(self, notification: types.ServerNotif...
FILE: src/mcp/client/session_group.py
class SseServerParameters (line 32) | class SseServerParameters(BaseModel):
class StreamableHttpParameters (line 48) | class StreamableHttpParameters(BaseModel):
class ClientSessionParameters (line 73) | class ClientSessionParameters:
class ClientSessionGroup (line 85) | class ClientSessionGroup:
class _ComponentNames (line 104) | class _ComponentNames(BaseModel):
method __init__ (line 128) | def __init__(
method __aenter__ (line 150) | async def __aenter__(self) -> Self: # pragma: no cover
method __aexit__ (line 156) | async def __aexit__(
method sessions (line 174) | def sessions(self) -> list[mcp.ClientSession]:
method prompts (line 179) | def prompts(self) -> dict[str, types.Prompt]:
method resources (line 184) | def resources(self) -> dict[str, types.Resource]:
method tools (line 189) | def tools(self) -> dict[str, types.Tool]:
method call_tool (line 193) | async def call_tool(
method disconnect_from_server (line 213) | async def disconnect_from_server(self, session: mcp.ClientSession) -> ...
method connect_with_session (line 248) | async def connect_with_session(
method connect_to_server (line 255) | async def connect_to_server(
method _establish_session (line 264) | async def _establish_session(
method _aggregate_components (line 332) | async def _aggregate_components(self, server_info: types.Implementatio...
method _component_name (line 407) | def _component_name(self, name: str, server_info: types.Implementation...
FILE: src/mcp/client/sse.py
function remove_request_params (line 21) | def remove_request_params(url: str) -> str:
function _extract_session_id_from_endpoint (line 25) | def _extract_session_id_from_endpoint(endpoint_url: str) -> str | None:
function sse_client (line 31) | async def sse_client(
FILE: src/mcp/client/stdio.py
function get_default_environment (line 51) | def get_default_environment() -> dict[str, str]:
class StdioServerParameters (line 71) | class StdioServerParameters(BaseModel):
function stdio_client (line 105) | async def stdio_client(server: StdioServerParameters, errlog: TextIO = s...
function _get_executable_command (line 214) | def _get_executable_command(command: str) -> str:
function _create_platform_compatible_process (line 229) | async def _create_platform_compatible_process(
function _terminate_process_tree (line 255) | async def _terminate_process_tree(process: Process | FallbackProcess, ti...
FILE: src/mcp/client/streamable_http.py
class StreamableHTTPError (line 53) | class StreamableHTTPError(Exception):
class ResumptionError (line 57) | class ResumptionError(StreamableHTTPError):
class RequestContext (line 62) | class RequestContext:
class StreamableHTTPTransport (line 72) | class StreamableHTTPTransport:
method __init__ (line 75) | def __init__(self, url: str) -> None:
method _prepare_headers (line 85) | def _prepare_headers(self) -> dict[str, str]:
method _is_initialization_request (line 102) | def _is_initialization_request(self, message: JSONRPCMessage) -> bool:
method _is_initialized_notification (line 106) | def _is_initialized_notification(self, message: JSONRPCMessage) -> bool:
method _maybe_extract_session_id_from_response (line 110) | def _maybe_extract_session_id_from_response(self, response: httpx.Resp...
method _maybe_extract_protocol_version_from_message (line 117) | def _maybe_extract_protocol_version_from_message(self, message: JSONRP...
method _handle_sse_event (line 129) | async def _handle_sse_event(
method handle_get_stream (line 181) | async def handle_get_stream(self, client: httpx.AsyncClient, read_stre...
method _handle_resumption_request (line 226) | async def _handle_resumption_request(self, ctx: RequestContext) -> None:
method _handle_post_request (line 254) | async def _handle_post_request(self, ctx: RequestContext) -> None:
method _handle_json_response (line 303) | async def _handle_json_response(
method _handle_sse_response (line 328) | async def _handle_sse_response(
method _handle_reconnection (line 374) | async def _handle_reconnection(
method post_writer (line 432) | async def post_writer(
method terminate_session (line 484) | async def terminate_session(self, client: httpx.AsyncClient) -> None:
method get_session_id (line 501) | def get_session_id(self) -> str | None:
function streamable_http_client (line 510) | async def streamable_http_client(
FILE: src/mcp/client/websocket.py
function websocket_client (line 16) | async def websocket_client(
FILE: src/mcp/os/posix/utilities.py
function terminate_posix_process_tree (line 13) | async def terminate_posix_process_tree(process: Process, timeout_seconds...
FILE: src/mcp/os/win32/utilities.py
function get_windows_executable_command (line 34) | def get_windows_executable_command(command: str) -> str:
class FallbackProcess (line 65) | class FallbackProcess:
method __init__ (line 74) | def __init__(self, popen_obj: subprocess.Popen[bytes]):
method __aenter__ (line 83) | async def __aenter__(self):
method __aexit__ (line 87) | async def __aexit__(
method wait (line 109) | async def wait(self):
method terminate (line 113) | def terminate(self):
method kill (line 117) | def kill(self) -> None:
method pid (line 122) | def pid(self) -> int:
method returncode (line 127) | def returncode(self) -> int | None:
function create_windows_process (line 137) | async def create_windows_process(
function _create_windows_fallback_process (line 195) | async def _create_windows_fallback_process(
function _create_job_object (line 232) | def _create_job_object() -> int | None:
function _maybe_assign_process_to_job (line 249) | def _maybe_assign_process_to_job(process: Process | FallbackProcess, job...
function terminate_windows_process_tree (line 278) | async def terminate_windows_process_tree(process: Process | FallbackProc...
function terminate_windows_process (line 316) | async def terminate_windows_process(process: Process | FallbackProcess):
FILE: src/mcp/server/__main__.py
function receive_loop (line 20) | async def receive_loop(session: ServerSession):
function main (line 30) | async def main():
FILE: src/mcp/server/auth/errors.py
function stringify_pydantic_error (line 4) | def stringify_pydantic_error(validation_error: ValidationError) -> str:
FILE: src/mcp/server/auth/handlers/authorize.py
class AuthorizationRequest (line 25) | class AuthorizationRequest(BaseModel):
class AuthorizationErrorResponse (line 45) | class AuthorizationErrorResponse(BaseModel):
function best_effort_extract_string (line 53) | def best_effort_extract_string(key: str, params: None | FormData | Query...
class AnyUrlModel (line 62) | class AnyUrlModel(RootModel[AnyUrl]):
class AuthorizationHandler (line 67) | class AuthorizationHandler:
method handle (line 70) | async def handle(self, request: Request) -> Response:
FILE: src/mcp/server/auth/handlers/metadata.py
class MetadataHandler (line 11) | class MetadataHandler:
method handle (line 14) | async def handle(self, request: Request) -> Response:
class ProtectedResourceMetadataHandler (line 22) | class ProtectedResourceMetadataHandler:
method handle (line 25) | async def handle(self, request: Request) -> Response:
FILE: src/mcp/server/auth/handlers/register.py
class RegistrationErrorResponse (line 22) | class RegistrationErrorResponse(BaseModel):
class RegistrationHandler (line 28) | class RegistrationHandler:
method handle (line 32) | async def handle(self, request: Request) -> Response:
FILE: src/mcp/server/auth/handlers/revoke.py
class RevocationRequest (line 17) | class RevocationRequest(BaseModel):
class RevocationErrorResponse (line 26) | class RevocationErrorResponse(BaseModel):
class RevocationHandler (line 32) | class RevocationHandler:
method handle (line 36) | async def handle(self, request: Request) -> Response:
FILE: src/mcp/server/auth/handlers/token.py
class AuthorizationCodeRequest (line 17) | class AuthorizationCodeRequest(BaseModel):
class RefreshTokenRequest (line 31) | class RefreshTokenRequest(BaseModel):
class TokenErrorResponse (line 47) | class TokenErrorResponse(BaseModel):
class TokenHandler (line 62) | class TokenHandler:
method response (line 66) | def response(self, obj: TokenSuccessResponse | TokenErrorResponse):
method handle (line 80) | async def handle(self, request: Request):
FILE: src/mcp/server/auth/json_response.py
class PydanticJSONResponse (line 6) | class PydanticJSONResponse(JSONResponse):
method render (line 9) | def render(self, content: Any) -> bytes:
FILE: src/mcp/server/auth/middleware/auth_context.py
function get_access_token (line 13) | def get_access_token() -> AccessToken | None:
class AuthContextMiddleware (line 23) | class AuthContextMiddleware:
method __init__ (line 32) | def __init__(self, app: ASGIApp):
method __call__ (line 35) | async def __call__(self, scope: Scope, receive: Receive, send: Send):
FILE: src/mcp/server/auth/middleware/bearer_auth.py
class AuthenticatedUser (line 13) | class AuthenticatedUser(SimpleUser):
method __init__ (line 16) | def __init__(self, auth_info: AccessToken):
class BearerAuthBackend (line 22) | class BearerAuthBackend(AuthenticationBackend):
method __init__ (line 25) | def __init__(self, token_verifier: TokenVerifier):
method authenticate (line 28) | async def authenticate(self, conn: HTTPConnection):
class RequireAuthMiddleware (line 50) | class RequireAuthMiddleware:
method __init__ (line 57) | def __init__(
method __call__ (line 74) | async def __call__(self, scope: Scope, receive: Receive, send: Send) -...
method _send_auth_error (line 94) | async def _send_auth_error(self, send: Send, status_code: int, error: ...
FILE: src/mcp/server/auth/middleware/client_auth.py
class AuthenticationError (line 14) | class AuthenticationError(Exception):
method __init__ (line 15) | def __init__(self, message: str):
class ClientAuthenticator (line 19) | class ClientAuthenticator:
method __init__ (line 31) | def __init__(self, provider: OAuthAuthorizationServerProvider[Any, Any...
method authenticate_request (line 39) | async def authenticate_request(self, request: Request) -> OAuthClientI...
FILE: src/mcp/server/auth/provider.py
class AuthorizationParams (line 10) | class AuthorizationParams(BaseModel):
class AuthorizationCode (line 19) | class AuthorizationCode(BaseModel):
class RefreshToken (line 30) | class RefreshToken(BaseModel):
class AccessToken (line 37) | class AccessToken(BaseModel):
class RegistrationError (line 54) | class RegistrationError(Exception):
class AuthorizeError (line 71) | class AuthorizeError(Exception):
class TokenError (line 87) | class TokenError(Exception):
class TokenVerifier (line 92) | class TokenVerifier(Protocol):
method verify_token (line 95) | async def verify_token(self, token: str) -> AccessToken | None:
class OAuthAuthorizationServerProvider (line 106) | class OAuthAuthorizationServerProvider(Protocol, Generic[AuthorizationCo...
method get_client (line 107) | async def get_client(self, client_id: str) -> OAuthClientInformationFu...
method register_client (line 120) | async def register_client(self, client_info: OAuthClientInformationFul...
method authorize (line 133) | async def authorize(self, client: OAuthClientInformationFull, params: ...
method load_authorization_code (line 176) | async def load_authorization_code(
method exchange_authorization_code (line 190) | async def exchange_authorization_code(
method load_refresh_token (line 207) | async def load_refresh_token(self, client: OAuthClientInformationFull,...
method exchange_refresh_token (line 219) | async def exchange_refresh_token(
method load_access_token (line 242) | async def load_access_token(self, token: str) -> AccessTokenT | None:
method revoke_token (line 252) | async def revoke_token(
function construct_redirect_uri (line 269) | def construct_redirect_uri(redirect_uri_base: str, **params: str | None)...
class ProviderTokenVerifier (line 280) | class ProviderTokenVerifier(TokenVerifier):
method __init__ (line 288) | def __init__(self, provider: "OAuthAuthorizationServerProvider[Authori...
method verify_token (line 291) | async def verify_token(self, token: str) -> AccessToken | None:
FILE: src/mcp/server/auth/routes.py
function validate_issuer_url (line 24) | def validate_issuer_url(url: AnyHttpUrl):
function cors_middleware (line 51) | def cors_middleware(
function create_auth_routes (line 64) | def create_auth_routes(
function build_metadata (line 145) | def build_metadata(
function build_resource_metadata_url (line 185) | def build_resource_metadata_url(resource_server_url: AnyHttpUrl) -> AnyH...
function create_protected_resource_routes (line 203) | def create_protected_resource_routes(
FILE: src/mcp/server/auth/settings.py
class ClientRegistrationOptions (line 4) | class ClientRegistrationOptions(BaseModel):
class RevocationOptions (line 11) | class RevocationOptions(BaseModel):
class AuthSettings (line 15) | class AuthSettings(BaseModel):
FILE: src/mcp/server/context.py
class ServerRequestContext (line 18) | class ServerRequestContext(RequestContext[ServerSession], Generic[Lifesp...
FILE: src/mcp/server/elicitation.py
class AcceptedElicitation (line 17) | class AcceptedElicitation(BaseModel, Generic[ElicitSchemaModelT]):
class DeclinedElicitation (line 24) | class DeclinedElicitation(BaseModel):
class CancelledElicitation (line 30) | class CancelledElicitation(BaseModel):
class AcceptedUrlElicitation (line 39) | class AcceptedUrlElicitation(BaseModel):
function _validate_elicitation_schema (line 52) | def _validate_elicitation_schema(schema: type[BaseModel]) -> None:
function _is_string_sequence (line 71) | def _is_string_sequence(annotation: type) -> bool:
function _is_primitive_field (line 87) | def _is_primitive_field(annotation: type) -> bool:
function elicit_with_validation (line 105) | async def elicit_with_validation(
function elicit_url (line 145) | async def elicit_url(
FILE: src/mcp/server/experimental/request_context.py
class Experimental (line 33) | class Experimental:
method is_task (line 48) | def is_task(self) -> bool:
method client_supports_tasks (line 53) | def client_supports_tasks(self) -> bool:
method validate_task_mode (line 59) | def validate_task_mode(
method validate_for_tool (line 95) | def validate_for_tool(self, tool: Tool, *, raise_error: bool = True) -...
method can_use_tool (line 110) | def can_use_tool(self, tool_task_mode: TaskExecutionMode | None) -> bool:
method run_task (line 127) | async def run_task(
FILE: src/mcp/server/experimental/session_features.py
class ExperimentalServerSessionFeatures (line 26) | class ExperimentalServerSessionFeatures:
method __init__ (line 39) | def __init__(self, session: "ServerSession") -> None:
method get_task (line 42) | async def get_task(self, task_id: str) -> types.GetTaskResult:
method get_task_result (line 56) | async def get_task_result(
method poll_task (line 75) | async def poll_task(self, task_id: str) -> AsyncIterator[types.GetTask...
method elicit_as_task (line 92) | async def elicit_as_task(
method create_message_as_task (line 140) | async def create_message_as_task(
FILE: src/mcp/server/experimental/task_context.py
class ServerTaskContext (line 50) | class ServerTaskContext:
method __init__ (line 75) | def __init__(
method task_id (line 102) | def task_id(self) -> str:
method task (line 107) | def task(self) -> Task:
method is_cancelled (line 112) | def is_cancelled(self) -> bool:
method request_cancellation (line 116) | def request_cancellation(self) -> None:
method update_status (line 122) | async def update_status(self, message: str, *, notify: bool = True) ->...
method complete (line 133) | async def complete(self, result: Result, *, notify: bool = True) -> None:
method fail (line 144) | async def fail(self, error: str, *, notify: bool = True) -> None:
method _send_notification (line 155) | async def _send_notification(self) -> None:
method _check_elicitation_capability (line 174) | def _check_elicitation_capability(self) -> None:
method _check_sampling_capability (line 179) | def _check_sampling_capability(self) -> None:
method elicit (line 184) | async def elicit(
method elicit_url (line 247) | async def elicit_url(
method create_message (line 315) | async def create_message(
method elicit_as_task (line 407) | async def elicit_as_task(
method create_message_as_task (line 484) | async def create_message_as_task(
FILE: src/mcp/server/experimental/task_result_handler.py
class TaskResultHandler (line 36) | class TaskResultHandler:
method __init__ (line 57) | def __init__(
method send_message (line 67) | async def send_message(
method handle (line 78) | async def handle(
method _deliver_queued_messages (line 128) | async def _deliver_queued_messages(
method _wait_for_task_update (line 160) | async def _wait_for_task_update(self, task_id: str) -> None:
method route_response (line 186) | def route_response(self, request_id: RequestId, response: dict[str, An...
method route_error (line 204) | def route_error(self, request_id: RequestId, error: ErrorData) -> bool:
FILE: src/mcp/server/experimental/task_support.py
class TaskSupport (line 22) | class TaskSupport:
method __post_init__ (line 55) | def __post_init__(self) -> None:
method task_group (line 60) | def task_group(self) -> TaskGroup:
method run (line 71) | async def run(self) -> AsyncIterator[None]:
method configure_session (line 89) | def configure_session(self, session: ServerSession) -> None:
method in_memory (line 104) | def in_memory(cls) -> "TaskSupport":
FILE: src/mcp/server/lowlevel/experimental.py
class ExperimentalHandlers (line 46) | class ExperimentalHandlers(Generic[LifespanResultT]):
method __init__ (line 52) | def __init__(
method task_support (line 64) | def task_support(self) -> TaskSupport | None:
method update_capabilities (line 68) | def update_capabilities(self, capabilities: ServerCapabilities) -> None:
method enable_tasks (line 83) | def enable_tasks(
FILE: src/mcp/server/lowlevel/helper_types.py
class ReadResourceContents (line 6) | class ReadResourceContents:
FILE: src/mcp/server/lowlevel/server.py
class NotificationOptions (line 77) | class NotificationOptions:
method __init__ (line 78) | def __init__(self, prompts_changed: bool = False, resources_changed: b...
function lifespan (line 85) | async def lifespan(_: Server[LifespanResultT]) -> AsyncIterator[dict[str...
function _ping_handler (line 94) | async def _ping_handler(ctx: ServerRequestContext[Any], params: types.Re...
class Server (line 98) | class Server(Generic[LifespanResultT]):
method __init__ (line 99) | def __init__(
method _add_request_handler (line 234) | def _add_request_handler(
method _has_handler (line 242) | def _has_handler(self, method: str) -> bool:
method create_initialization_options (line 251) | def create_initialization_options(
method get_capabilities (line 280) | def get_capabilities(
method experimental (line 328) | def experimental(self) -> ExperimentalHandlers[LifespanResultT]:
method session_manager (line 343) | def session_manager(self) -> StreamableHTTPSessionManager:
method run (line 356) | async def run(
method _handle_message (line 401) | async def _handle_message(
method _handle_request (line 425) | async def _handle_request(
method _handle_notification (line 486) | async def _handle_notification(
method streamable_http_app (line 512) | def streamable_http_app(
FILE: src/mcp/server/mcpserver/context.py
class Context (line 22) | class Context(BaseModel, Generic[LifespanContextT, RequestT]):
method __init__ (line 60) | def __init__(
method mcp_server (line 73) | def mcp_server(self) -> MCPServer:
method request_context (line 80) | def request_context(self) -> ServerRequestContext[LifespanContextT, Re...
method report_progress (line 86) | async def report_progress(self, progress: float, total: float | None =...
method read_resource (line 107) | async def read_resource(self, uri: str | AnyUrl) -> Iterable[ReadResou...
method elicit (line 119) | async def elicit(
method elicit_url (line 152) | async def elicit_url(
method log (line 187) | async def log(
method client_id (line 217) | def client_id(self) -> str | None:
method request_id (line 222) | def request_id(self) -> str:
method session (line 227) | def session(self):
method close_sse_stream (line 231) | async def close_sse_stream(self) -> None:
method close_standalone_sse_stream (line 248) | async def close_standalone_sse_stream(self) -> None:
method debug (line 264) | async def debug(self, message: str, *, logger_name: str | None = None,...
method info (line 268) | async def info(self, message: str, *, logger_name: str | None = None, ...
method warning (line 272) | async def warning(
method error (line 278) | async def error(self, message: str, *, logger_name: str | None = None,...
FILE: src/mcp/server/mcpserver/exceptions.py
class MCPServerError (line 4) | class MCPServerError(Exception):
class ValidationError (line 8) | class ValidationError(MCPServerError):
class ResourceError (line 12) | class ResourceError(MCPServerError):
class ToolError (line 16) | class ToolError(MCPServerError):
class InvalidSignature (line 20) | class InvalidSignature(Exception):
FILE: src/mcp/server/mcpserver/prompts/base.py
class Message (line 21) | class Message(BaseModel):
method __init__ (line 27) | def __init__(self, content: str | ContentBlock, **kwargs: Any):
class UserMessage (line 33) | class UserMessage(Message):
method __init__ (line 38) | def __init__(self, content: str | ContentBlock, **kwargs: Any):
class AssistantMessage (line 42) | class AssistantMessage(Message):
method __init__ (line 47) | def __init__(self, content: str | ContentBlock, **kwargs: Any):
class PromptArgument (line 57) | class PromptArgument(BaseModel):
class Prompt (line 65) | class Prompt(BaseModel):
method from_function (line 77) | def from_function(
method render (line 136) | async def render(
FILE: src/mcp/server/mcpserver/prompts/manager.py
class PromptManager (line 17) | class PromptManager:
method __init__ (line 20) | def __init__(self, warn_on_duplicate_prompts: bool = True):
method get_prompt (line 24) | def get_prompt(self, name: str) -> Prompt | None:
method list_prompts (line 28) | def list_prompts(self) -> list[Prompt]:
method add_prompt (line 32) | def add_prompt(
method render_prompt (line 48) | async def render_prompt(
FILE: src/mcp/server/mcpserver/resources/base.py
class Resource (line 17) | class Resource(BaseModel, abc.ABC):
method set_default_name (line 33) | def set_default_name(cls, name: str | None, info: ValidationInfo) -> str:
method read (line 42) | async def read(self) -> str | bytes:
FILE: src/mcp/server/mcpserver/resources/resource_manager.py
class ResourceManager (line 22) | class ResourceManager:
method __init__ (line 25) | def __init__(self, warn_on_duplicate_resources: bool = True):
method add_resource (line 30) | def add_resource(self, resource: Resource) -> Resource:
method add_template (line 56) | def add_template(
method get_resource (line 83) | async def get_resource(self, uri: AnyUrl | str, context: Context[Lifes...
method list_resources (line 102) | def list_resources(self) -> list[Resource]:
method list_templates (line 107) | def list_templates(self) -> list[ResourceTemplate]:
FILE: src/mcp/server/mcpserver/resources/templates.py
class ResourceTemplate (line 23) | class ResourceTemplate(BaseModel):
method from_function (line 39) | def from_function(
method matches (line 85) | def matches(self, uri: str) -> dict[str, Any] | None:
method create_resource (line 98) | async def create_resource(
FILE: src/mcp/server/mcpserver/resources/types.py
class TextResource (line 20) | class TextResource(Resource):
method read (line 25) | async def read(self) -> str:
class BinaryResource (line 30) | class BinaryResource(Resource):
method read (line 35) | async def read(self) -> bytes:
class FunctionResource (line 40) | class FunctionResource(Resource):
method read (line 55) | async def read(self) -> str | bytes:
method from_function (line 76) | def from_function(
class FileResource (line 109) | class FileResource(Resource):
method validate_absolute_path (line 127) | def validate_absolute_path(cls, path: Path) -> Path:
method set_binary_from_mime_type (line 135) | def set_binary_from_mime_type(cls, is_binary: bool, info: ValidationIn...
method read (line 142) | async def read(self) -> str | bytes:
class HttpResource (line 152) | class HttpResource(Resource):
method read (line 158) | async def read(self) -> str | bytes:
class DirectoryResource (line 166) | class DirectoryResource(Resource):
method validate_absolute_path (line 176) | def validate_absolute_path(cls, path: Path) -> Path: # pragma: no cover
method list_files (line 182) | def list_files(self) -> list[Path]: # pragma: no cover
method read (line 196) | async def read(self) -> str: # Always returns JSON string # pragma: ...
FILE: src/mcp/server/mcpserver/server.py
class Settings (line 80) | class Settings(BaseSettings, Generic[LifespanResultT]):
function lifespan_wrapper (line 114) | def lifespan_wrapper(
class MCPServer (line 126) | class MCPServer(Generic[LifespanResultT]):
method __init__ (line 127) | def __init__(
method name (line 201) | def name(self) -> str:
method title (line 205) | def title(self) -> str | None:
method description (line 209) | def description(self) -> str | None:
method instructions (line 213) | def instructions(self) -> str | None:
method website_url (line 217) | def website_url(self) -> str | None:
method icons (line 221) | def icons(self) -> list[Icon] | None:
method version (line 225) | def version(self) -> str | None:
method session_manager (line 229) | def session_manager(self) -> StreamableHTTPSessionManager:
method run (line 241) | def run(self, transport: Literal["stdio"] = ...) -> None: ...
method run (line 244) | def run(
method run (line 256) | def run(
method run (line 270) | def run(
method _handle_list_tools (line 293) | async def _handle_list_tools(
method _handle_call_tool (line 298) | async def _handle_call_tool(
method _handle_list_resources (line 326) | async def _handle_list_resources(
method _handle_read_resource (line 331) | async def _handle_read_resource(
method _handle_list_resource_templates (line 358) | async def _handle_list_resource_templates(
method _handle_list_prompts (line 363) | async def _handle_list_prompts(
method _handle_get_prompt (line 368) | async def _handle_get_prompt(
method list_tools (line 374) | async def list_tools(self) -> list[MCPTool]:
method call_tool (line 391) | async def call_tool(
method list_resources (line 399) | async def list_resources(self) -> list[MCPResource]:
method list_resource_templates (line 417) | async def list_resource_templates(self) -> list[MCPResourceTemplate]:
method read_resource (line 433) | async def read_resource(
method add_tool (line 452) | def add_tool(
method remove_tool (line 492) | def remove_tool(self, name: str) -> None:
method tool (line 503) | def tool(
method completion (line 573) | def completion(self):
method add_resource (line 610) | def add_resource(self, resource: Resource) -> None:
method resource (line 618) | def resource(
method add_prompt (line 730) | def add_prompt(self, prompt: Prompt) -> None:
method prompt (line 738) | def prompt(
method custom_route (line 796) | def custom_route(
method run_stdio_async (line 839) | async def run_stdio_async(self) -> None:
method run_sse_async (line 848) | async def run_sse_async( # pragma: no cover
method run_streamable_http_async (line 876) | async def run_streamable_http_async( # pragma: no cover
method sse_app (line 910) | def sse_app(
method streamable_http_app (line 1036) | def streamable_http_app(
method list_prompts (line 1063) | async def list_prompts(self) -> list[MCPPrompt]:
method get_prompt (line 1084) | async def get_prompt(
FILE: src/mcp/server/mcpserver/tools/base.py
class Tool (line 23) | class Tool(BaseModel):
method output_schema (line 41) | def output_schema(self) -> dict[str, Any] | None:
method from_function (line 45) | def from_function(
method run (line 92) | async def run(
function _is_async_callable (line 123) | def _is_async_callable(obj: Any) -> bool:
FILE: src/mcp/server/mcpserver/tools/tool_manager.py
class ToolManager (line 18) | class ToolManager:
method __init__ (line 21) | def __init__(
method get_tool (line 36) | def get_tool(self, name: str) -> Tool | None:
method list_tools (line 40) | def list_tools(self) -> list[Tool]:
method add_tool (line 44) | def add_tool(
method remove_tool (line 74) | def remove_tool(self, name: str) -> None:
method call_tool (line 80) | async def call_tool(
FILE: src/mcp/server/mcpserver/utilities/context_injection.py
function find_context_parameter (line 13) | def find_context_parameter(fn: Callable[..., Any]) -> str | None:
function inject_context (line 49) | def inject_context(
FILE: src/mcp/server/mcpserver/utilities/func_metadata.py
class StrictJsonSchema (line 32) | class StrictJsonSchema(GenerateJsonSchema):
method emit_warning (line 38) | def emit_warning(self, kind: JsonSchemaWarningKind, detail: str) -> None:
class ArgModelBase (line 43) | class ArgModelBase(BaseModel):
method model_dump_one_level (line 46) | def model_dump_one_level(self) -> dict[str, Any]:
class FuncMetadata (line 62) | class FuncMetadata(BaseModel):
method call_fn_with_arg_validation (line 68) | async def call_fn_with_arg_validation(
method convert_result (line 91) | def convert_result(self, result: Any) -> Any:
method pre_parse_json (line 125) | def pre_parse_json(self, data: dict[str, Any]) -> dict[str, Any]:
function func_metadata (line 170) | def func_metadata(
function _try_create_model_and_schema (line 322) | def _try_create_model_and_schema(
function _create_model_from_class (line 422) | def _create_model_from_class(cls: type[Any], type_hints: dict[str, Any])...
function _create_model_from_typeddict (line 446) | def _create_model_from_typeddict(td_type: type[Any]) -> type[BaseModel]:
function _create_wrapped_model (line 467) | def _create_wrapped_model(func_name: str, annotation: Any) -> type[BaseM...
function _create_dict_model (line 477) | def _create_dict_model(func_name: str, dict_annotation: Any) -> type[Bas...
function _convert_to_content (line 492) | def _convert_to_content(result: Any) -> Sequence[ContentBlock]:
FILE: src/mcp/server/mcpserver/utilities/logging.py
function get_logger (line 7) | def get_logger(name: str) -> logging.Logger:
function configure_logging (line 19) | def configure_logging(
FILE: src/mcp/server/mcpserver/utilities/types.py
class Image (line 9) | class Image:
method __init__ (line 12) | def __init__(
method _get_mime_type (line 28) | def _get_mime_type(self) -> str:
method to_image_content (line 44) | def to_image_content(self) -> ImageContent:
class Audio (line 57) | class Audio:
method __init__ (line 60) | def __init__(
method _get_mime_type (line 74) | def _get_mime_type(self) -> str:
method to_audio_content (line 91) | def to_audio_content(self) -> AudioContent:
FILE: src/mcp/server/models.py
class InitializationOptions (line 10) | class InitializationOptions(BaseModel):
FILE: src/mcp/server/session.py
class InitializationState (line 54) | class InitializationState(Enum):
class ServerSession (line 67) | class ServerSession(
method __init__ (line 80) | def __init__(
method _receive_request_adapter (line 100) | def _receive_request_adapter(self) -> TypeAdapter[types.ClientRequest]:
method _receive_notification_adapter (line 104) | def _receive_notification_adapter(self) -> TypeAdapter[types.ClientNot...
method client_params (line 108) | def client_params(self) -> types.InitializeRequestParams | None:
method experimental (line 112) | def experimental(self) -> ExperimentalServerSessionFeatures:
method check_client_capability (line 121) | def check_client_capability(self, capability: types.ClientCapabilities...
method _receive_loop (line 160) | async def _receive_loop(self) -> None:
method _received_request (line 164) | async def _received_request(self, responder: RequestResponder[types.Cl...
method _received_notification (line 196) | async def _received_notification(self, notification: types.ClientNotif...
method send_log_message (line 206) | async def send_log_message(
method send_resource_updated (line 225) | async def send_resource_updated(self, uri: str | AnyUrl) -> None: # p...
method create_message (line 234) | async def create_message(
method create_message (line 253) | async def create_message(
method create_message (line 271) | async def create_message(
method list_roots (line 348) | async def list_roots(self) -> types.ListRootsResult:
method elicit (line 357) | async def elicit(
method elicit_form (line 379) | async def elicit_form(
method elicit_url (line 411) | async def elicit_url(
method send_ping (line 449) | async def send_ping(self) -> types.EmptyResult: # pragma: no cover
method send_progress_notification (line 456) | async def send_progress_notification(
method send_resource_list_changed (line 477) | async def send_resource_list_changed(self) -> None:
method send_tool_list_changed (line 481) | async def send_tool_list_changed(self) -> None: # pragma: no cover
method send_prompt_list_changed (line 485) | async def send_prompt_list_changed(self) -> None: # pragma: no cover
method send_elicit_complete (line 489) | async def send_elicit_complete(
method _build_elicit_form_request (line 511) | def _build_elicit_form_request(
method _build_elicit_url_request (line 556) | def _build_elicit_url_request(
method _build_create_message_request (line 601) | def _build_create_message_request(
method send_message (line 671) | async def send_message(self, message: SessionMessage) -> None:
method _handle_incoming (line 686) | async def _handle_incoming(self, req: ServerRequestResponder) -> None:
method incoming_messages (line 690) | def incoming_messages(self) -> MemoryObjectReceiveStream[ServerRequest...
FILE: src/mcp/server/sse.py
class SseServerTransport (line 63) | class SseServerTransport:
method __init__ (line 78) | def __init__(self, endpoint: str, security_settings: TransportSecurity...
method connect_sse (line 119) | async def connect_sse(self, scope: Scope, receive: Receive, send: Send...
method handle_post_message (line 198) | async def handle_post_message(self, scope: Scope, receive: Receive, se...
FILE: src/mcp/server/stdio.py
function stdio_server (line 33) | async def stdio_server(stdin: anyio.AsyncFile[str] | None = None, stdout...
FILE: src/mcp/server/streamable_http.py
class EventMessage (line 70) | class EventMessage:
class EventStore (line 80) | class EventStore(ABC):
method store_event (line 84) | async def store_event(self, stream_id: StreamId, message: JSONRPCMessa...
method replay_events_after (line 97) | async def replay_events_after(
class StreamableHTTPServerTransport (line 114) | class StreamableHTTPServerTransport:
method __init__ (line 128) | def __init__(
method is_terminated (line 176) | def is_terminated(self) -> bool:
method close_sse_stream (line 180) | def close_sse_stream(self, request_id: RequestId) -> None: # pragma: ...
method close_standalone_sse_stream (line 208) | def close_standalone_sse_stream(self) -> None: # pragma: no cover
method _create_session_message (line 227) | def _create_session_message(
method _maybe_send_priming_event (line 259) | async def _maybe_send_priming_event(
method _create_error_response (line 285) | def _create_error_response(
method _create_json_response (line 313) | def _create_json_response(
method _get_session_id (line 333) | def _get_session_id(self, request: Request) -> str | None:
method _create_event_data (line 337) | def _create_event_data(self, event_message: EventMessage) -> dict[str,...
method _clean_up_memory_streams (line 350) | async def _clean_up_memory_streams(self, request_id: RequestId) -> None:
method handle_request (line 364) | async def handle_request(self, scope: Scope, receive: Receive, send: S...
method _check_accept_headers (line 393) | def _check_accept_headers(self, request: Request) -> tuple[bool, bool]:
method _check_content_type (line 410) | def _check_content_type(self, request: Request) -> bool:
method _validate_accept_header (line 417) | async def _validate_accept_header(self, request: Request, scope: Scope...
method _handle_post_request (line 439) | async def _handle_post_request(self, scope: Scope, request: Request, r...
method _handle_get_request (line 648) | async def _handle_get_request(self, request: Request, send: Send) -> N...
method _handle_delete_request (line 740) | async def _handle_delete_request(self, request: Request, send: Send) -...
method terminate (line 763) | async def terminate(self) -> None:
method _handle_unsupported_request (line 794) | async def _handle_unsupported_request(self, request: Request, send: Se...
method _validate_request_headers (line 810) | async def _validate_request_headers(self, request: Request, send: Send...
method _validate_session (line 817) | async def _validate_session(self, request: Request, send: Send) -> bool:
method _validate_protocol_version (line 846) | async def _validate_protocol_version(self, request: Request, send: Sen...
method _replay_events (line 868) | async def _replay_events(self, last_event_id: str, request: Request, s...
method connect (line 953) | async def connect(
FILE: src/mcp/server/streamable_http_manager.py
class StreamableHTTPSessionManager (line 32) | class StreamableHTTPSessionManager:
method __init__ (line 66) | def __init__(
method run (line 100) | async def run(self) -> AsyncIterator[None]:
method handle_request (line 139) | async def handle_request(self, scope: Scope, receive: Receive, send: S...
method _handle_stateless_request (line 153) | async def _handle_stateless_request(self, scope: Scope, receive: Recei...
method _handle_stateful_request (line 190) | async def _handle_stateful_request(self, scope: Scope, receive: Receiv...
class StreamableHTTPASGIApp (line 289) | class StreamableHTTPASGIApp:
method __init__ (line 292) | def __init__(self, session_manager: StreamableHTTPSessionManager):
method __call__ (line 295) | async def __call__(self, scope: Scope, receive: Receive, send: Send) -...
FILE: src/mcp/server/transport_security.py
class TransportSecuritySettings (line 13) | class TransportSecuritySettings(BaseModel):
class TransportSecurityMiddleware (line 36) | class TransportSecurityMiddleware:
method __init__ (line 39) | def __init__(self, settings: TransportSecuritySettings | None = None):
method _validate_host (line 43) | def _validate_host(self, host: str | None) -> bool: # pragma: no cover
method _validate_origin (line 65) | def _validate_origin(self, origin: str | None) -> bool: # pragma: no ...
method _validate_content_type (line 87) | def _validate_content_type(self, content_type: str | None) -> bool:
method validate_request (line 91) | async def validate_request(self, request: Request, is_post: bool = Fal...
FILE: src/mcp/server/validation.py
function check_sampling_tools_capability (line 11) | def check_sampling_tools_capability(client_caps: ClientCapabilities | No...
function validate_sampling_tools (line 29) | def validate_sampling_tools(
function validate_tool_use_result_messages (line 49) | def validate_tool_use_result_messages(messages: list[SamplingMessage]) -...
FILE: src/mcp/server/websocket.py
function websocket_server (line 14) | async def websocket_server(scope: Scope, receive: Receive, send: Send):
FILE: src/mcp/shared/_context.py
class RequestContext (line 15) | class RequestContext(Generic[SessionT]):
FILE: src/mcp/shared/_httpx_utils.py
class McpHttpClientFactory (line 14) | class McpHttpClientFactory(Protocol): # pragma: no branch
method __call__ (line 15) | def __call__( # pragma: no branch
function create_mcp_http_client (line 23) | def create_mcp_http_client(
FILE: src/mcp/shared/auth.py
class OAuthToken (line 6) | class OAuthToken(BaseModel):
method normalize_token_type (line 17) | def normalize_token_type(cls, v: str | None) -> str | None:
class InvalidScopeError (line 25) | class InvalidScopeError(Exception):
method __init__ (line 26) | def __init__(self, message: str):
class InvalidRedirectUriError (line 30) | class InvalidRedirectUriError(Exception):
method __init__ (line 31) | def __init__(self, message: str):
class OAuthClientMetadata (line 35) | class OAuthClientMetadata(BaseModel):
method validate_scope (line 70) | def validate_scope(self, requested_scope: str | None) -> list[str] | N...
method validate_redirect_uri (line 80) | def validate_redirect_uri(self, redirect_uri: AnyUrl | None) -> AnyUrl:
class OAuthClientInformationFull (line 92) | class OAuthClientInformationFull(OAuthClientMetadata):
class OAuthMetadata (line 103) | class OAuthMetadata(BaseModel):
class ProtectedResourceMetadata (line 132) | class ProtectedResourceMetadata(BaseModel):
FILE: src/mcp/shared/auth_utils.py
function resource_url_from_server_url (line 9) | def resource_url_from_server_url(url: str | HttpUrl | AnyUrl) -> str:
function check_resource_allowed (line 31) | def check_resource_allowed(requested_resource: str, configured_resource:...
function calculate_token_expiry (line 68) | def calculate_token_expiry(expires_in: int | str | None) -> float | None:
FILE: src/mcp/shared/exceptions.py
class MCPError (line 8) | class MCPError(Exception):
method __init__ (line 13) | def __init__(self, code: int, message: str, data: Any = None):
method code (line 21) | def code(self) -> int:
method message (line 25) | def message(self) -> str:
method data (line 29) | def data(self) -> Any:
method from_jsonrpc_error (line 33) | def from_jsonrpc_error(cls, error: JSONRPCError) -> MCPError:
method from_error_data (line 37) | def from_error_data(cls, error: ErrorData) -> MCPError:
method __str__ (line 40) | def __str__(self) -> str:
class StatelessModeNotSupported (line 44) | class StatelessModeNotSupported(RuntimeError):
method __init__ (line 52) | def __init__(self, method: str):
class UrlElicitationRequiredError (line 61) | class UrlElicitationRequiredError(MCPError):
method __init__ (line 79) | def __init__(self, elicitations: list[ElicitRequestURLParams], message...
method elicitations (line 93) | def elicitations(self) -> list[ElicitRequestURLParams]:
method from_error (line 98) | def from_error(cls, error: ErrorData) -> UrlElicitationRequiredError:
FILE: src/mcp/shared/experimental/tasks/capabilities.py
function check_tasks_capability (line 14) | def check_tasks_capability(
function has_task_augmented_elicitation (line 51) | def has_task_augmented_elicitation(caps: ClientCapabilities) -> bool:
function has_task_augmented_sampling (line 62) | def has_task_augmented_sampling(caps: ClientCapabilities) -> bool:
function require_task_augmented_elicitation (line 73) | def require_task_augmented_elicitation(client_caps: ClientCapabilities |...
function require_task_augmented_sampling (line 86) | def require_task_augmented_sampling(client_caps: ClientCapabilities | No...
FILE: src/mcp/shared/experimental/tasks/context.py
class TaskContext (line 12) | class TaskContext:
method __init__ (line 34) | def __init__(self, task: Task, store: TaskStore):
method task_id (line 40) | def task_id(self) -> str:
method task (line 45) | def task(self) -> Task:
method is_cancelled (line 50) | def is_cancelled(self) -> bool:
method request_cancellation (line 54) | def request_cancellation(self) -> None:
method update_status (line 62) | async def update_status(self, message: str) -> None:
method complete (line 73) | async def complete(self, result: Result) -> None:
method fail (line 85) | async def fail(self, error: str) -> None:
FILE: src/mcp/shared/experimental/tasks/helpers.py
function is_terminal (line 36) | def is_terminal(status: TaskStatus) -> bool:
function cancel_task (line 50) | async def cancel_task(
function generate_task_id (line 92) | def generate_task_id() -> str:
function create_task_state (line 97) | def create_task_state(
function task_execution (line 124) | async def task_execution(
FILE: src/mcp/shared/experimental/tasks/in_memory_task_store.py
class StoredTask (line 21) | class StoredTask:
class InMemoryTaskStore (line 30) | class InMemoryTaskStore(TaskStore):
method __init__ (line 46) | def __init__(self, page_size: int = 10) -> None:
method _calculate_expiry (line 51) | def _calculate_expiry(self, ttl_ms: int | None) -> datetime | None:
method _is_expired (line 57) | def _is_expired(self, stored: StoredTask) -> bool:
method _cleanup_expired (line 63) | def _cleanup_expired(self) -> None:
method create_task (line 69) | async def create_task(
method get_task (line 92) | async def get_task(self, task_id: str) -> Task | None:
method update_task (line 104) | async def update_task(
method store_result (line 140) | async def store_result(self, task_id: str, result: Result) -> None:
method get_result (line 148) | async def get_result(self, task_id: str) -> Result | None:
method list_tasks (line 156) | async def list_tasks(
method delete_task (line 184) | async def delete_task(self, task_id: str) -> bool:
method wait_for_update (line 192) | async def wait_for_update(self, task_id: str) -> None:
method notify_update (line 202) | async def notify_update(self, task_id: str) -> None:
method cleanup (line 209) | def cleanup(self) -> None:
method get_all_tasks (line 214) | def get_all_tasks(self) -> list[Task]:
FILE: src/mcp/shared/experimental/tasks/message_queue.py
class QueuedMessage (line 27) | class QueuedMessage:
class TaskMessageQueue (line 50) | class TaskMessageQueue(ABC):
method enqueue (line 65) | async def enqueue(self, task_id: str, message: QueuedMessage) -> None:
method dequeue (line 74) | async def dequeue(self, task_id: str) -> QueuedMessage | None:
method peek (line 85) | async def peek(self, task_id: str) -> QueuedMessage | None:
method is_empty (line 96) | async def is_empty(self, task_id: str) -> bool:
method clear (line 107) | async def clear(self, task_id: str) -> list[QueuedMessage]:
method wait_for_message (line 120) | async def wait_for_message(self, task_id: str) -> None:
method notify_message_available (line 132) | async def notify_message_available(self, task_id: str) -> None:
class InMemoryTaskMessageQueue (line 142) | class InMemoryTaskMessageQueue(TaskMessageQueue):
method __init__ (line 154) | def __init__(self) -> None:
method _get_queue (line 158) | def _get_queue(self, task_id: str) -> deque[QueuedMessage]:
method enqueue (line 164) | async def enqueue(self, task_id: str, message: QueuedMessage) -> None:
method dequeue (line 171) | async def dequeue(self, task_id: str) -> QueuedMessage | None:
method peek (line 178) | async def peek(self, task_id: str) -> QueuedMessage | None:
method is_empty (line 185) | async def is_empty(self, task_id: str) -> bool:
method clear (line 190) | async def clear(self, task_id: str) -> list[QueuedMessage]:
method wait_for_message (line 197) | async def wait_for_message(self, task_id: str) -> None:
method notify_message_available (line 214) | async def notify_message_available(self, task_id: str) -> None:
method cleanup (line 219) | def cleanup(self, task_id: str | None = None) -> None:
FILE: src/mcp/shared/experimental/tasks/polling.py
function poll_until_terminal (line 17) | async def poll_until_terminal(
FILE: src/mcp/shared/experimental/tasks/resolver.py
class Resolver (line 14) | class Resolver(Generic[T]):
method __init__ (line 29) | def __init__(self) -> None:
method set_result (line 34) | def set_result(self, value: T) -> None:
method set_exception (line 41) | def set_exception(self, exc: BaseException) -> None:
method wait (line 48) | async def wait(self) -> T:
method done (line 56) | def done(self) -> bool:
FILE: src/mcp/shared/experimental/tasks/store.py
class TaskStore (line 8) | class TaskStore(ABC):
method create_task (line 18) | async def create_task(
method get_task (line 37) | async def get_task(self, task_id: str) -> Task | None:
method update_task (line 48) | async def update_task(
method store_result (line 72) | async def store_result(self, task_id: str, result: Result) -> None:
method get_result (line 84) | async def get_result(self, task_id: str) -> Result | None:
method list_tasks (line 95) | async def list_tasks(
method delete_task (line 109) | async def delete_task(self, task_id: str) -> bool:
method wait_for_update (line 120) | async def wait_for_update(self, task_id: str) -> None:
method notify_update (line 137) | async def notify_update(self, task_id: str) -> None:
FILE: src/mcp/shared/memory.py
function create_client_server_memory_streams (line 17) | async def create_client_server_memory_streams() -> AsyncGenerator[tuple[...
FILE: src/mcp/shared/message.py
class ClientMessageMetadata (line 22) | class ClientMessageMetadata:
class ServerMessageMetadata (line 30) | class ServerMessageMetadata:
class SessionMessage (line 48) | class SessionMessage:
FILE: src/mcp/shared/metadata_utils.py
function get_display_name (line 10) | def get_display_name(obj: Tool | Resource | Prompt | ResourceTemplate | ...
FILE: src/mcp/shared/response_router.py
class ResponseRouter (line 21) | class ResponseRouter(Protocol):
method route_response (line 39) | def route_response(self, request_id: RequestId, response: dict[str, An...
method route_error (line 51) | def route_error(self, request_id: RequestId, error: ErrorData) -> bool:
FILE: src/mcp/shared/session.py
class ProgressFnT (line 48) | class ProgressFnT(Protocol):
method __call__ (line 51) | async def __call__(
class RequestResponder (line 56) | class RequestResponder(Generic[ReceiveRequestT, SendResultT]):
method __init__ (line 74) | def __init__(
method __enter__ (line 93) | def __enter__(self) -> RequestResponder[ReceiveRequestT, SendResultT]:
method __exit__ (line 100) | def __exit__(
method respond (line 116) | async def respond(self, response: SendResultT | ErrorData) -> None:
method cancel (line 136) | async def cancel(self) -> None:
method in_flight (line 152) | def in_flight(self) -> bool: # pragma: no cover
method cancelled (line 156) | def cancelled(self) -> bool:
class BaseSession (line 160) | class BaseSession(
method __init__ (line 182) | def __init__(
method add_response_router (line 199) | def add_response_router(self, router: ResponseRouter) -> None:
method __aenter__ (line 214) | async def __aenter__(self) -> Self:
method __aexit__ (line 220) | async def __aexit__(
method send_request (line 233) | async def send_request(
method send_notification (line 292) | async def send_notification(
method _send_response (line 310) | async def _send_response(self, request_id: RequestId, response: SendRe...
method _receive_request_adapter (line 325) | def _receive_request_adapter(self) -> TypeAdapter[ReceiveRequestT]:
method _receive_notification_adapter (line 330) | def _receive_notification_adapter(self) -> TypeAdapter[ReceiveNotifica...
method _receive_loop (line 333) | async def _receive_loop(self) -> None:
method _normalize_request_id (line 431) | def _normalize_request_id(self, response_id: RequestId) -> RequestId:
method _handle_response (line 451) | async def _handle_response(self, message: SessionMessage) -> None:
method _received_request (line 493) | async def _received_request(self, responder: RequestResponder[ReceiveR...
method _received_notification (line 501) | async def _received_notification(self, notification: ReceiveNotificati...
method send_progress_notification (line 506) | async def send_progress_notification(
method _handle_incoming (line 515) | async def _handle_incoming(
FILE: src/mcp/shared/tool_name_validation.py
class ToolNameValidationResult (line 28) | class ToolNameValidationResult:
function validate_tool_name (line 40) | def validate_tool_name(name: str) -> ToolNameValidationResult:
function issue_tool_name_warning (line 97) | def issue_tool_name_warning(name: str, warnings: list[str]) -> None:
function validate_and_warn_tool_name (line 115) | def validate_and_warn_tool_name(name: str) -> bool:
FILE: src/mcp/types/_types.py
class MCPModel (line 39) | class MCPModel(BaseModel):
class RequestParamsMeta (line 48) | class RequestParamsMeta(TypedDict, extra_items=Any):
class TaskMetadata (line 58) | class TaskMetadata(MCPModel):
class RequestParams (line 68) | class RequestParams(MCPModel):
class PaginatedRequestParams (line 82) | class PaginatedRequestParams(RequestParams):
class NotificationParams (line 90) | class NotificationParams(MCPModel):
class Request (line 103) | class Request(MCPModel, Generic[RequestParamsT, MethodT]):
class PaginatedRequest (line 110) | class PaginatedRequest(Request[PaginatedRequestParams | None, MethodT], ...
class Notification (line 116) | class Notification(MCPModel, Generic[NotificationParamsT, MethodT]):
class Result (line 123) | class Result(MCPModel):
class PaginatedResult (line 133) | class PaginatedResult(Result):
class EmptyResult (line 141) | class EmptyResult(Result):
class BaseMetadata (line 145) | class BaseMetadata(MCPModel):
class Icon (line 162) | class Icon(MCPModel):
class Implementation (line 184) | class Implementation(BaseMetadata):
class RootsCapability (line 202) | class RootsCapability(MCPModel):
class SamplingContextCapability (line 209) | class SamplingContextCapability(MCPModel):
class SamplingToolsCapability (line 217) | class SamplingToolsCapability(MCPModel):
class FormElicitationCapability (line 225) | class FormElicitationCapability(MCPModel):
class UrlElicitationCapability (line 229) | class UrlElicitationCapability(MCPModel):
class ElicitationCapability (line 233) | class ElicitationCapability(MCPModel):
class SamplingCapability (line 246) | class SamplingCapability(MCPModel):
class TasksListCapability (line 261) | class TasksListCapability(MCPModel):
class TasksCancelCapability (line 265) | class TasksCancelCapability(MCPModel):
class TasksCreateMessageCapability (line 269) | class TasksCreateMessageCapability(MCPModel):
class TasksSamplingCapability (line 273) | class TasksSamplingCapability(MCPModel):
class TasksCreateElicitationCapability (line 279) | class TasksCreateElicitationCapability(MCPModel):
class TasksElicitationCapability (line 283) | class TasksElicitationCapability(MCPModel):
class ClientTasksRequestsCapability (line 289) | class ClientTasksRequestsCapability(MCPModel):
class ClientTasksCapability (line 297) | class ClientTasksCapability(MCPModel):
class ClientCapabilities (line 310) | class ClientCapabilities(MCPModel):
class PromptsCapability (line 328) | class PromptsCapability(MCPModel):
class ResourcesCapability (line 335) | class ResourcesCapability(MCPModel):
class ToolsCapability (line 344) | class ToolsCapability(MCPModel):
class LoggingCapability (line 351) | class LoggingCapability(MCPModel):
class CompletionsCapability (line 355) | class CompletionsCapability(MCPModel):
class TasksCallCapability (line 359) | class TasksCallCapability(MCPModel):
class TasksToolsCapability (line 363) | class TasksToolsCapability(MCPModel):
class ServerTasksRequestsCapability (line 369) | class ServerTasksRequestsCapability(MCPModel):
class ServerTasksCapability (line 375) | class ServerTasksCapability(MCPModel):
class ServerCapabilities (line 383) | class ServerCapabilities(MCPModel):
class RelatedTaskMetadata (line 418) | class RelatedTaskMetadata(MCPModel):
class Task (line 428) | class Task(MCPModel):
class CreateTaskResult (line 459) | class CreateTaskResult(Result):
class GetTaskRequestParams (line 465) | class GetTaskRequestParams(RequestParams):
class GetTaskRequest (line 470) | class GetTaskRequest(Request[GetTaskRequestParams, Literal["tasks/get"]]):
class GetTaskResult (line 478) | class GetTaskResult(Result, Task):
class GetTaskPayloadRequestParams (line 482) | class GetTaskPayloadRequestParams(RequestParams):
class GetTaskPayloadRequest (line 487) | class GetTaskPayloadRequest(Request[GetTaskPayloadRequestParams, Literal...
class GetTaskPayloadResult (line 494) | class GetTaskPayloadResult(Result):
class CancelTaskRequestParams (line 504) | class CancelTaskRequestParams(RequestParams):
class CancelTaskRequest (line 509) | class CancelTaskRequest(Request[CancelTaskRequestParams, Literal["tasks/...
class CancelTaskResult (line 516) | class CancelTaskResult(Result, Task):
class ListTasksRequest (line 520) | class ListTasksRequest(PaginatedRequest[Literal["tasks/list"]]):
class ListTasksResult (line 526) | class ListTasksResult(PaginatedResult):
class TaskStatusNotificationParams (line 532) | class TaskStatusNotificationParams(NotificationParams, Task):
class TaskStatusNotification (line 536) | class TaskStatusNotification(Notification[TaskStatusNotificationParams, ...
class InitializeRequestParams (line 545) | class InitializeRequestParams(RequestParams):
class InitializeRequest (line 554) | class InitializeRequest(Request[InitializeRequestParams, Literal["initia...
class InitializeResult (line 563) | class InitializeResult(Result):
class InitializedNotification (line 574) | class InitializedNotification(Notification[NotificationParams | None, Li...
class PingRequest (line 583) | class PingRequest(Request[RequestParams | None, Literal["ping"]]):
class ProgressNotificationParams (line 592) | class ProgressNotificationParams(NotificationParams):
class ProgressNotification (line 614) | class ProgressNotification(Notification[ProgressNotificationParams, Lite...
class ListResourcesRequest (line 621) | class ListResourcesRequest(PaginatedRequest[Literal["resources/list"]]):
class Annotations (line 627) | class Annotations(MCPModel):
class Resource (line 632) | class Resource(BaseMetadata):
class ResourceTemplate (line 662) | class ResourceTemplate(BaseMetadata):
class ListResourcesResult (line 689) | class ListResourcesResult(PaginatedResult):
class ListResourceTemplatesRequest (line 695) | class ListResourceTemplatesRequest(PaginatedRequest[Literal["resources/t...
class ListResourceTemplatesResult (line 701) | class ListResourceTemplatesResult(PaginatedResult):
class ReadResourceRequestParams (line 707) | class ReadResourceRequestParams(RequestParams):
class ReadResourceRequest (line 717) | class ReadResourceRequest(Request[ReadResourceRequestParams, Literal["re...
class ResourceContents (line 724) | class ResourceContents(MCPModel):
class TextResourceContents (line 738) | class TextResourceContents(ResourceContents):
class BlobResourceContents (line 748) | class BlobResourceContents(ResourceContents):
class ReadResourceResult (line 755) | class ReadResourceResult(Result):
class ResourceListChangedNotification (line 761) | class ResourceListChangedNotification(
class SubscribeRequestParams (line 772) | class SubscribeRequestParams(RequestParams):
class SubscribeRequest (line 782) | class SubscribeRequest(Request[SubscribeRequestParams, Literal["resource...
class UnsubscribeRequestParams (line 791) | class UnsubscribeRequestParams(RequestParams):
class UnsubscribeRequest (line 798) | class UnsubscribeRequest(Request[UnsubscribeRequestParams, Literal["reso...
class ResourceUpdatedNotificationParams (line 807) | class ResourceUpdatedNotificationParams(NotificationParams):
class ResourceUpdatedNotification (line 817) | class ResourceUpdatedNotification(
class ListPromptsRequest (line 828) | class ListPromptsRequest(PaginatedRequest[Literal["prompts/list"]]):
class PromptArgument (line 834) | class PromptArgument(MCPModel):
class Prompt (line 845) | class Prompt(BaseMetadata):
class ListPromptsResult (line 861) | class ListPromptsResult(PaginatedResult):
class GetPromptRequestParams (line 867) | class GetPromptRequestParams(RequestParams):
class GetPromptRequest (line 876) | class GetPromptRequest(Request[GetPromptRequestParams, Literal["prompts/...
class TextContent (line 883) | class TextContent(MCPModel):
class ImageContent (line 897) | class ImageContent(MCPModel):
class AudioContent (line 916) | class AudioContent(MCPModel):
class ToolUseContent (line 935) | class ToolUseContent(MCPModel):
class ToolResultContent (line 962) | class ToolResultContent(MCPModel):
class SamplingMessage (line 1006) | class SamplingMessage(MCPModel):
method content_as_list (line 1022) | def content_as_list(self) -> list[SamplingMessageContentBlock]:
class EmbeddedResource (line 1028) | class EmbeddedResource(MCPModel):
class ResourceLink (line 1045) | class ResourceLink(Resource):
class PromptMessage (line 1058) | class PromptMessage(MCPModel):
class GetPromptResult (line 1065) | class GetPromptResult(Result):
class PromptListChangedNotification (line 1073) | class PromptListChangedNotification(
class ListToolsRequest (line 1084) | class ListToolsRequest(PaginatedRequest[Literal["tools/list"]]):
class ToolAnnotations (line 1090) | class ToolAnnotations(MCPModel):
class ToolExecution (line 1136) | class ToolExecution(MCPModel):
class Tool (line 1153) | class Tool(BaseMetadata):
class ListToolsResult (line 1178) | class ListToolsResult(PaginatedResult):
class CallToolRequestParams (line 1184) | class CallToolRequestParams(RequestParams):
class CallToolRequest (line 1191) | class CallToolRequest(Request[CallToolRequestParams, Literal["tools/call...
class CallToolResult (line 1198) | class CallToolResult(Result):
class ToolListChangedNotification (line 1207) | class ToolListChangedNotification(Notification[NotificationParams | None...
class SetLevelRequestParams (line 1219) | class SetLevelRequestParams(RequestParams):
class SetLevelRequest (line 1226) | class SetLevelRequest(Request[SetLevelRequestParams, Literal["logging/se...
class LoggingMessageNotificationParams (line 1233) | class LoggingMessageNotificationParams(NotificationParams):
class LoggingMessageNotification (line 1247) | class LoggingMessageNotification(Notification[LoggingMessageNotification...
class ModelHint (line 1257) | class ModelHint(MCPModel):
class ModelPreferences (line 1264) | class ModelPreferences(MCPModel):
class ToolChoice (line 1312) | class ToolChoice(MCPModel):
class CreateMessageRequestParams (line 1328) | class CreateMessageRequestParams(RequestParams):
class CreateMessageRequest (line 1362) | class CreateMessageRequest(Request[CreateMessageRequestParams, Literal["...
class CreateMessageResult (line 1372) | class CreateMessageResult(Result):
class CreateMessageResultWithTools (line 1389) | class CreateMessageResultWithTools(Result):
method content_as_list (line 1411) | def content_as_list(self) -> list[SamplingMessageContentBlock]:
class ResourceTemplateReference (line 1417) | class ResourceTemplateReference(MCPModel):
class PromptReference (line 1425) | class PromptReference(MCPModel):
class CompletionArgument (line 1433) | class CompletionArgument(MCPModel):
class CompletionContext (line 1442) | class CompletionContext(MCPModel):
class CompleteRequestParams (line 1449) | class CompleteRequestParams(RequestParams):
class CompleteRequest (line 1458) | class CompleteRequest(Request[CompleteRequestParams, Literal["completion...
class Completion (line 1465) | class Completion(MCPModel):
class CompleteResult (line 1482) | class CompleteResult(Result):
class ListRootsRequest (line 1488) | class ListRootsRequest(Request[RequestParams | None, Literal["roots/list...
class Root (line 1502) | class Root(MCPModel):
class ListRootsResult (line 1524) | class ListRootsResult(Result):
class RootsListChangedNotification (line 1534) | class RootsListChangedNotification(
class CancelledNotificationParams (line 1549) | class CancelledNotificationParams(NotificationParams):
class CancelledNotification (line 1564) | class CancelledNotification(Notification[CancelledNotificationParams, Li...
class ElicitCompleteNotificationParams (line 1573) | class ElicitCompleteNotificationParams(NotificationParams):
class ElicitCompleteNotification (line 1580) | class ElicitCompleteNotification(
class ElicitRequestFormParams (line 1633) | class ElicitRequestFormParams(RequestParams):
class ElicitRequestURLParams (line 1653) | class ElicitRequestURLParams(RequestParams):
class ElicitRequest (line 1681) | class ElicitRequest(Request[ElicitRequestParams, Literal["elicitation/cr...
class ElicitResult (line 1688) | class ElicitResult(Result):
class ElicitationRequiredErrorData (line 1708) | class ElicitationRequiredErrorData(MCPModel):
FILE: src/mcp/types/jsonrpc.py
class JSONRPCRequest (line 13) | class JSONRPCRequest(BaseModel):
class JSONRPCNotification (line 22) | class JSONRPCNotification(BaseModel):
class JSONRPCResponse (line 31) | class JSONRPCResponse(BaseModel):
class ErrorData (line 55) | class ErrorData(BaseModel):
class JSONRPCError (line 74) | class JSONRPCError(BaseModel):
FILE: tests/cli/test_claude.py
function config_dir (line 13) | def config_dir(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Path:
function _read_server (line 22) | def _read_server(config_dir: Path, name: str) -> dict[str, Any]:
function test_generates_uv_run_command (line 27) | def test_generates_uv_run_command(config_dir: Path):
function test_file_spec_without_object_suffix (line 38) | def test_file_spec_without_object_suffix(config_dir: Path):
function test_with_packages_sorted_and_deduplicated (line 45) | def test_with_packages_sorted_and_deduplicated(config_dir: Path):
function test_with_editable_adds_flag (line 53) | def test_with_editable_adds_flag(config_dir: Path, tmp_path: Path):
function test_env_vars_written (line 62) | def test_env_vars_written(config_dir: Path):
function test_existing_env_vars_merged_new_wins (line 69) | def test_existing_env_vars_merged_new_wins(config_dir: Path):
function test_existing_env_vars_preserved_without_new (line 80) | def test_existing_env_vars_preserved_without_new(config_dir: Path):
function test_other_servers_preserved (line 89) | def test_other_servers_preserved(config_dir: Path):
function test_raises_when_config_dir_missing (line 100) | def test_raises_when_config_dir_missing(monkeypatch: pytest.MonkeyPatch):
function test_get_uv_path (line 110) | def test_get_uv_path(monkeypatch: pytest.MonkeyPatch, which_result: str ...
function test_windows_drive_letter_not_split (line 127) | def test_windows_drive_letter_not_split(
FILE: tests/cli/test_utils.py
function test_parse_file_path_accepts_valid_specs (line 18) | def test_parse_file_path_accepts_valid_specs(tmp_path: Path, spec: str, ...
function test_parse_file_path_missing (line 27) | def test_parse_file_path_missing(tmp_path: Path):
function test_parse_file_exit_on_dir (line 33) | def test_parse_file_exit_on_dir(tmp_path: Path):
function test_build_uv_command_minimal (line 41) | def test_build_uv_command_minimal():
function test_build_uv_command_adds_editable_and_packages (line 47) | def test_build_uv_command_adds_editable_and_packages():
function test_get_npx_unix_like (line 72) | def test_get_npx_unix_like(monkeypatch: pytest.MonkeyPatch):
function test_get_npx_windows (line 78) | def test_get_npx_windows(monkeypatch: pytest.MonkeyPatch):
function test_get_npx_returns_none_when_npx_missing (line 93) | def test_get_npx_returns_none_when_npx_missing(monkeypatch: pytest.Monke...
FILE: tests/client/auth/extensions/test_client_credentials.py
class MockTokenStorage (line 19) | class MockTokenStorage:
method __init__ (line 22) | def __init__(self):
method get_tokens (line 26) | async def get_tokens(self) -> OAuthToken | None:
method set_tokens (line 29) | async def set_tokens(self, tokens: OAuthToken) -> None: # pragma: no ...
method get_client_info (line 32) | async def get_client_info(self) -> OAuthClientInformationFull | None: ...
method set_client_info (line 35) | async def set_client_info(self, client_info: OAuthClientInformationFul...
function mock_storage (line 40) | def mock_storage():
function client_metadata (line 45) | def client_metadata():
function rfc7523_oauth_provider (line 55) | def rfc7523_oauth_provider(client_metadata: OAuthClientMetadata, mock_st...
class TestOAuthFlowClientCredentials (line 75) | class TestOAuthFlowClientCredentials:
method test_token_exchange_request_jwt_predefined (line 79) | async def test_token_exchange_request_jwt_predefined(self, rfc7523_oau...
method test_token_exchange_request_jwt (line 118) | async def test_token_exchange_request_jwt(self, rfc7523_oauth_provider...
class TestClientCredentialsOAuthProvider (line 176) | class TestClientCredentialsOAuthProvider:
method test_init_sets_client_info (line 180) | async def test_init_sets_client_info(self, mock_storage: MockTokenStor...
method test_init_with_scopes (line 199) | async def test_init_with_scopes(self, mock_storage: MockTokenStorage):
method test_init_with_client_secret_post (line 214) | async def test_init_with_client_secret_post(self, mock_storage: MockTo...
method test_exchange_token_client_credentials (line 229) | async def test_exchange_token_client_credentials(self, mock_storage: M...
method test_exchange_token_client_secret_post_includes_client_id (line 256) | async def test_exchange_token_client_secret_post_includes_client_id(se...
method test_exchange_token_client_secret_post_without_client_id (line 284) | async def test_exchange_token_client_secret_post_without_client_id(sel...
method test_exchange_token_without_scopes (line 322) | async def test_exchange_token_without_scopes(self, mock_storage: MockT...
class TestPrivateKeyJWTOAuthProvider (line 345) | class TestPrivateKeyJWTOAuthProvider:
method test_init_sets_client_info (line 349) | async def test_init_sets_client_info(self, mock_storage: MockTokenStor...
method test_exchange_token_client_credentials (line 371) | async def test_exchange_token_client_credentials(self, mock_storage: M...
method test_exchange_token_without_scopes (line 403) | async def test_exchange_token_without_scopes(self, mock_storage: MockT...
class TestSignedJWTParameters (line 430) | class TestSignedJWTParameters:
method test_create_assertion_provider (line 434) | async def test_create_assertion_provider(self):
method test_create_assertion_provider_with_additional_claims (line 461) | async def test_create_assertion_provider_with_additional_claims(self):
class TestStaticAssertionProvider (line 483) | class TestStaticAssertionProvider:
method test_returns_static_token (line 487) | async def test_returns_static_token(self):
FILE: tests/client/conftest.py
class SpyMemoryObjectSendStream (line 14) | class SpyMemoryObjectSendStream:
method __init__ (line 15) | def __init__(self, original_stream: MemoryObjectSendStream[SessionMess...
method send (line 19) | async def send(self, message: SessionMessage):
method aclose (line 23) | async def aclose(self):
method __aenter__ (line 26) | async def __aenter__(self):
method __aexit__ (line 29) | async def __aexit__(self, *args: Any):
class StreamSpyCollection (line 33) | class StreamSpyCollection:
method __init__ (line 34) | def __init__(self, client_spy: SpyMemoryObjectSendStream, server_spy: ...
method clear (line 38) | def clear(self) -> None:
method get_client_requests (line 43) | def get_client_requests(self, method: str | None = None) -> list[JSONR...
method get_server_requests (line 51) | def get_server_requests(self, method: str | None = None) -> list[JSONR...
method get_client_notifications (line 59) | def get_client_notifications(self, method: str | None = None) -> list[...
method get_server_notifications (line 67) | def get_server_notifications(self, method: str | None = None) -> list[...
function stream_spy (line 77) | def stream_spy() -> Generator[Callable[[], StreamSpyCollection], None, N...
FILE: tests/client/test_auth.py
class MockTokenStorage (line 40) | class MockTokenStorage:
method __init__ (line 43) | def __init__(self):
method get_tokens (line 47) | async def get_tokens(self) -> OAuthToken | None:
method set_tokens (line 50) | async def set_tokens(self, tokens: OAuthToken) -> None:
method get_client_info (line 53) | async def get_client_info(self) -> OAuthClientInformationFull | None:
method set_client_info (line 56) | async def set_client_info(self, client_info: OAuthClientInformationFul...
function mock_storage (line 61) | def mock_storage():
function client_metadata (line 66) | def client_metadata():
function valid_tokens (line 76) | def valid_tokens():
function oauth_provider (line 87) | def oauth_provider(client_metadata: OAuthClientMetadata, mock_storage: M...
function prm_metadata_response (line 106) | def prm_metadata_response():
function prm_metadata_without_scopes_response (line 119) | def prm_metadata_without_scopes_response():
function init_response_with_www_auth_scope (line 132) | def init_response_with_www_auth_scope():
function init_response_without_www_auth_scope (line 142) | def init_response_without_www_auth_scope():
class TestPKCEParameters (line 151) | class TestPKCEParameters:
method test_pkce_generation (line 154) | def test_pkce_generation(self):
method test_pkce_uniqueness (line 169) | def test_pkce_uniqueness(self):
class TestOAuthContext (line 178) | class TestOAuthContext:
method test_oauth_provider_initialization (line 182) | async def test_oauth_provider_initialization(
method test_context_url_parsing (line 192) | def test_context_url_parsing(self, oauth_provider: OAuthClientProvider):
method test_token_validity_checking (line 214) | async def test_token_validity_checking(self, oauth_provider: OAuthClie...
method test_clear_tokens (line 249) | def test_clear_tokens(self, oauth_provider: OAuthClientProvider, valid...
class TestOAuthFlow (line 263) | class TestOAuthFlow:
method test_build_protected_resource_discovery_urls (line 267) | async def test_build_protected_resource_discovery_urls(
method test_create_oauth_metadata_request (line 310) | def test_create_oauth_metadata_request(self, oauth_provider: OAuthClie...
class TestOAuthFallback (line 320) | class TestOAuthFallback:
method test_oauth_discovery_legacy_fallback_when_no_prm (line 324) | async def test_oauth_discovery_legacy_fallback_when_no_prm(self):
method test_oauth_discovery_path_aware_when_auth_server_has_path (line 335) | async def test_oauth_discovery_path_aware_when_auth_server_has_path(se...
method test_oauth_discovery_root_when_auth_server_has_no_path (line 349) | async def test_oauth_discovery_root_when_auth_server_has_no_path(self):
method test_oauth_discovery_root_when_auth_server_has_only_slash (line 362) | async def test_oauth_discovery_root_when_auth_server_has_only_slash(se...
method test_oauth_discovery_fallback_order (line 375) | async def test_oauth_discovery_fallback_order(self, oauth_provider: OA...
method test_oauth_discovery_fallback_conditions (line 391) | async def test_oauth_discovery_fallback_conditions(self, oauth_provide...
method test_handle_metadata_response_success (line 510) | async def test_handle_metadata_response_success(self, oauth_provider: ...
method test_prioritize_www_auth_scope_over_prm (line 526) | async def test_prioritize_www_auth_scope_over_prm(
method test_prioritize_prm_scopes_when_no_www_auth_scope (line 546) | async def test_prioritize_prm_scopes_when_no_www_auth_scope(
method test_omit_scope_when_no_prm_scopes_or_www_auth (line 566) | async def test_omit_scope_when_no_prm_scopes_or_www_auth(
method test_token_exchange_request_authorization_code (line 585) | async def test_token_exchange_request_authorization_code(self, oauth_p...
method test_refresh_token_request (line 610) | async def test_refresh_token_request(self, oauth_provider: OAuthClient...
method test_basic_auth_token_exchange (line 635) | async def test_basic_auth_token_exchange(self, oauth_provider: OAuthCl...
method test_basic_auth_refresh_token (line 680) | async def test_basic_auth_refresh_token(self, oauth_provider: OAuthCli...
method test_none_auth_method (line 715) | async def test_none_auth_method(self, oauth_provider: OAuthClientProvi...
class TestProtectedResourceMetadata (line 743) | class TestProtectedResourceMetadata:
method test_resource_param_included_with_recent_protocol_version (line 747) | async def test_resource_param_included_with_recent_protocol_version(se...
method test_resource_param_excluded_with_old_protocol_version (line 776) | async def test_resource_param_excluded_with_old_protocol_version(self,...
method test_resource_param_included_with_protected_resource_metadata (line 802) | async def test_resource_param_included_with_protected_resource_metadat...
function test_validate_resource_rejects_mismatched_resource (line 823) | async def test_validate_resource_rejects_mismatched_resource(
function test_validate_resource_accepts_matching_resource (line 843) | async def test_validate_resource_accepts_matching_resource(
function test_validate_resource_custom_callback (line 863) | async def test_validate_resource_custom_callback(
function test_validate_resource_accepts_root_url_with_trailing_slash (line 891) | async def test_validate_resource_accepts_root_url_with_trailing_slash(
function test_validate_resource_accepts_server_url_with_trailing_slash (line 911) | async def test_validate_resource_accepts_server_url_with_trailing_slash(
function test_get_resource_url_uses_canonical_when_prm_mismatches (line 931) | async def test_get_resource_url_uses_canonical_when_prm_mismatches(
class TestRegistrationResponse (line 952) | class TestRegistrationResponse:
method test_handle_registration_response_reads_before_accessing_text (line 956) | async def test_handle_registration_response_reads_before_accessing_tex...
class TestCreateClientRegistrationRequest (line 988) | class TestCreateClientRegistrationRequest:
method test_uses_registration_endpoint_from_metadata (line 991) | def test_uses_registration_endpoint_from_metadata(self):
method test_falls_back_to_default_register_endpoint_when_no_metadata (line 1006) | def test_falls_back_to_default_register_endpoint_when_no_metadata(self):
method test_falls_back_when_metadata_has_no_registration_endpoint (line 1015) | def test_falls_back_when_metadata_has_no_registration_endpoint(self):
class TestAuthFlow (line 1031) | class TestAuthFlow:
method test_auth_flow_with_valid_tokens (line 1035) | async def test_auth_flow_with_valid_tokens(
method test_auth_flow_with_no_tokens (line 1063) | async def test_auth_flow_with_no_tokens(self, oauth_provider: OAuthCli...
method test_auth_flow_no_unnecessary_retry_after_oauth (line 1171) | async def test_auth_flow_no_unnecessary_retry_after_oauth(
method test_token_exchange_accepts_201_status (line 1214) | async def test_token_exchange_accepts_201_status(
method test_403_insufficient_scope_updates_scope_from_header (line 1324) | async def test_403_insufficient_scope_updates_scope_from_header(
function test_build_metadata (line 1458) | def test_build_metadata(
class TestLegacyServerFallback (line 1490) | class TestLegacyServerFallback:
method test_legacy_server_no_prm_falls_back_to_root_oauth_discovery (line 1494) | async def test_legacy_server_no_prm_falls_back_to_root_oauth_discovery(
method test_legacy_server_with_different_prm_and_root_urls (line 1593) | async def test_legacy_server_with_different_prm_and_root_urls(
class TestSEP985Discovery (line 1694) | class TestSEP985Discovery:
method test_path_based_fallback_when_no_www_authenticate (line 1698) | async def test_path_based_fallback_when_no_www_authenticate(
method test_root_based_fallback_after_path_based_404 (line 1733) | async def test_root_based_fallback_after_path_based_404(
method test_www_authenticate_takes_priority_over_well_known (line 1834) | async def test_www_authenticate_takes_priority_over_well_known(
class TestWWWAuthenticate (line 1874) | class TestWWWAuthenticate:
method test_extract_field_from_www_auth_valid_cases (line 1923) | def test_extract_field_from_www_auth_valid_cases(
method test_extract_field_from_www_auth_invalid_cases (line 1957) | def test_extract_field_from_www_auth_invalid_cases(
class TestCIMD (line 1976) | class TestCIMD:
method test_is_valid_client_metadata_url (line 1999) | def test_is_valid_client_metadata_url(self, url: str | None, expected:...
method test_should_use_client_metadata_url_when_server_supports (line 2003) | def test_should_use_client_metadata_url_when_server_supports(self):
method test_should_not_use_client_metadata_url_when_server_does_not_support (line 2013) | def test_should_not_use_client_metadata_url_when_server_does_not_suppo...
method test_should_not_use_client_metadata_url_when_not_provided (line 2023) | def test_should_not_use_client_metadata_url_when_not_provided(self):
method test_should_not_use_client_metadata_url_when_no_metadata (line 2033) | def test_should_not_use_client_metadata_url_when_no_metadata(self):
method test_create_client_info_from_metadata_url (line 2037) | def test_create_client_info_from_metadata_url(self):
method test_oauth_provider_with_valid_client_metadata_url (line 2048) | def test_oauth_provider_with_valid_client_metadata_url(
method test_oauth_provider_with_invalid_client_metadata_url_raises_error (line 2069) | def test_oauth_provider_with_invalid_client_metadata_url_raises_error(
method test_auth_flow_uses_cimd_when_server_supports (line 2092) | async def test_auth_flow_uses_cimd_when_server_supports(
method test_auth_flow_falls_back_to_dcr_when_no_cimd_support (line 2183) | async def test_auth_flow_falls_back_to_dcr_when_no_cimd_support(
FILE: tests/client/test_client.py
function simple_server (line 42) | def simple_server() -> Server:
function app (line 77) | def app() -> MCPServer:
function test_client_is_initialized (line 99) | async def test_client_is_initialized(app: MCPServer):
function test_client_with_simple_server (line 113) | async def test_client_with_simple_server(simple_server: Server):
function test_client_send_ping (line 124) | async def test_client_send_ping(app: MCPServer):
function test_client_list_tools (line 130) | async def test_client_list_tools(app: MCPServer):
function test_client_call_tool (line 157) | async def test_client_call_tool(app: MCPServer):
function test_read_resource (line 168) | async def test_read_resource(app: MCPServer):
function test_read_resource_error_propagates (line 179) | async def test_read_resource_error_propagates():
function test_get_prompt (line 194) | async def test_get_prompt(app: MCPServer):
function test_client_session_property_before_enter (line 206) | def test_client_session_property_before_enter(app: MCPServer):
function test_client_reentry_raises_runtime_error (line 213) | async def test_client_reentry_raises_runtime_error(app: MCPServer):
function test_client_send_progress_notification (line 220) | async def test_client_send_progress_notification():
function test_client_subscribe_resource (line 238) | async def test_client_subscribe_resource(simple_server: Server):
function test_client_unsubscribe_resource (line 244) | async def test_client_unsubscribe_resource(simple_server: Server):
function test_client_set_logging_level (line 250) | async def test_client_set_logging_level(simple_server: Server):
function test_client_list_resources_with_params (line 257) | async def test_client_list_resources_with_params(app: MCPServer):
function test_client_list_resource_templates (line 275) | async def test_client_list_resource_templates(app: MCPServer):
function test_list_prompts (line 282) | async def test_list_prompts(app: MCPServer):
function test_complete_with_prompt_reference (line 299) | async def test_complete_with_prompt_reference(simple_server: Server):
function test_client_with_url_initializes_streamable_http_transport (line 307) | def test_client_with_url_initializes_streamable_http_transport():
function test_client_uses_transport_directly (line 313) | async def test_client_uses_transport_directly(app: MCPServer):
FILE: tests/client/test_http_unicode.py
function run_unicode_server (line 44) | def run_unicode_server(port: int) -> None: # pragma: no cover
function unicode_server_port (line 152) | def unicode_server_port() -> int:
function running_unicode_server (line 160) | def running_unicode_server(unicode_server_port: int) -> Generator[str, N...
function test_streamable_http_client_unicode_tool_call (line 180) | async def test_streamable_http_client_unicode_tool_call(running_unicode_...
function test_streamable_http_client_unicode_prompts (line 212) | async def test_streamable_http_client_unicode_prompts(running_unicode_se...
FILE: tests/client/test_list_methods_cursor.py
function full_featured_server (line 16) | async def full_featured_server():
function test_list_methods_params_parameter (line 55) | async def test_list_methods_params_parameter(
function test_list_tools_with_strict_server_validation (line 96) | async def test_list_tools_with_strict_server_validation(
function test_list_tools_with_lowlevel_server (line 106) | async def test_list_tools_with_lowlevel_server():
FILE: tests/client/test_list_roots_callback.py
function test_list_roots_callback (line 12) | async def test_list_roots_callback():
FILE: tests/client/test_logging_callback.py
class LoggingCollector (line 14) | class LoggingCollector:
method __init__ (line 15) | def __init__(self):
method __call__ (line 18) | async def __call__(self, params: LoggingMessageNotificationParams) -> ...
function test_logging_callback (line 23) | async def test_logging_callback():
FILE: tests/client/test_notification_response.py
function _init_json_response (line 30) | def _init_json_response(data: dict[str, object]) -> JSONResponse:
function _create_non_sdk_server_app (line 34) | def _create_non_sdk_server_app() -> Starlette:
function _create_unexpected_content_type_app (line 55) | def _create_unexpected_content_type_app() -> Starlette:
function test_non_compliant_notification_response (line 74) | async def test_non_compliant_notification_response() -> None:
function test_unexpected_content_type_sends_jsonrpc_error (line 103) | async def test_unexpected_content_type_sends_jsonrpc_error() -> None:
function _create_http_error_app (line 119) | def _create_http_error_app(error_status: int, *, error_on_notifications:...
function test_http_error_status_sends_jsonrpc_error (line 139) | async def test_http_error_status_sends_jsonrpc_error() -> None:
function test_http_error_on_notification_does_not_hang (line 155) | async def test_http_error_on_notification_does_not_hang() -> None:
function _create_invalid_json_response_app (line 171) | def _create_invalid_json_response_app() -> Starlette:
function test_invalid_json_response_sends_jsonrpc_error (line 190) | async def test_invalid_json_response_sends_jsonrpc_error() -> None:
FILE: tests/client/test_output_schema_validation.py
function _make_server (line 18) | def _make_server(
function test_tool_structured_output_client_side_validation_basemodel (line 37) | async def test_tool_structured_output_client_side_validation_basemodel():
function test_tool_structured_output_client_side_validation_primitive (line 65) | async def test_tool_structured_output_client_side_validation_primitive():
function test_tool_structured_output_client_side_validation_dict_typed (line 93) | async def test_tool_structured_output_client_side_validation_dict_typed():
function test_tool_structured_output_client_side_validation_missing_required (line 116) | async def test_tool_structured_output_client_side_validation_missing_req...
function test_tool_not_listed_warning (line 144) | async def test_tool_not_listed_warning(caplog: pytest.LogCaptureFixture):
FILE: tests/client/test_resource_cleanup.py
function test_send_request_stream_cleanup (line 14) | async def test_send_request_stream_cleanup():
FILE: tests/client/test_sampling_callback.py
function test_sampling_callback (line 18) | async def test_sampling_callback():
function test_create_message_backwards_compat_single_content (line 61) | async def test_create_message_backwards_compat_single_content():
function test_create_message_result_with_tools_type (line 103) | async def test_create_message_result_with_tools_type():
FILE: tests/client/test_scope_bug_1630.py
class MockTokenStorage (line 17) | class MockTokenStorage:
method __init__ (line 20) | def __init__(self) -> None:
method get_tokens (line 24) | async def get_tokens(self) -> OAuthToken | None:
method set_tokens (line 27) | async def set_tokens(self, tokens: OAuthToken) -> None:
method get_client_info (line 30) | async def get_client_info(self) -> OAuthClientInformationFull | None:
method set_client_info (line 33) | async def set_client_info(self, client_info: OAuthClientInformationFul...
function test_401_uses_www_auth_scope_not_resource_metadata_url (line 38) | async def test_401_uses_www_auth_scope_not_resource_metadata_url():
FILE: tests/client/test_session.py
function test_client_session_initialize (line 31) | async def test_client_session_initialize():
function test_client_session_custom_client_info (line 114) | async def test_client_session_custom_client_info():
function test_client_session_default_client_info (line 172) | async def test_client_session_default_client_info():
function test_client_session_version_negotiation_success (line 225) | async def test_client_session_version_negotiation_success():
function test_client_session_version_negotiation_failure (line 281) | async def test_client_session_version_negotiation_failure():
function test_client_capabilities_default (line 329) | async def test_client_capabilities_default():
function test_client_capabilities_with_custom_callbacks (line 385) | async def test_client_capabilities_with_custom_callbacks():
function test_client_capabilities_with_sampling_tools (line 469) | async def test_client_capabilities_with_sampling_tools():
function test_initialize_result (line 543) | async def test_initialize_result():
function test_client_tool_call_with_meta (line 611) | async def test_client_tool_call_with_meta(meta: RequestParamsMeta | None):
FILE: tests/client/test_session_group.py
function mock_exit_stack (line 20) | def mock_exit_stack():
function test_client_session_group_init (line 28) | def test_client_session_group_init():
function test_client_session_group_component_properties (line 36) | def test_client_session_group_component_properties():
function test_client_session_group_call_tool (line 55) | async def test_client_session_group_call_tool():
function test_client_session_group_connect_to_server (line 90) | async def test_client_session_group_connect_to_server(mock_exit_stack: c...
function test_client_session_group_connect_to_server_with_name_hook (line 129) | async def test_client_session_group_connect_to_server_with_name_hook(moc...
function test_client_session_group_disconnect_from_server (line 160) | async def test_client_session_group_disconnect_from_server():
function test_client_session_group_connect_to_server_duplicate_tool_raises_error (line 225) | async def test_client_session_group_connect_to_server_duplicate_tool_rai...
function test_client_session_group_disconnect_non_existent_server (line 273) | async def test_client_session_group_disconnect_non_existent_server():
function test_client_session_group_establish_session_parameterized (line 303) | async def test_client_session_group_establish_session_parameterized(
FILE: tests/client/test_stdio.py
function test_stdio_context_manager_exiting (line 34) | async def test_stdio_context_manager_exiting():
function test_stdio_client (line 42) | async def test_stdio_client():
function test_stdio_client_bad_path (line 74) | async def test_stdio_client_bad_path():
function test_stdio_client_nonexistent_command (line 89) | async def test_stdio_client_nonexistent_command():
function test_stdio_client_universal_cleanup (line 107) | async def test_stdio_client_universal_cleanup():
function test_stdio_client_sigint_only_process (line 159) | async def test_stdio_client_sigint_only_process(): # pragma: lax no cover
function _connect_back_script (line 247) | def _connect_back_script(port: int) -> str:
function _spawn_then_block (line 259) | def _spawn_then_block(child_script: str) -> str:
function _open_liveness_listener (line 268) | async def _open_liveness_listener() -> tuple[anyio.abc.SocketListener, i...
function _accept_alive (line 279) | async def _accept_alive(sock: anyio.abc.SocketListener) -> anyio.abc.Soc...
function _assert_stream_closed (line 292) | async def _assert_stream_closed(stream: anyio.abc.SocketStream) -> None:
function _terminate_and_reap (line 310) | async def _terminate_and_reap(proc: anyio.abc.Process | FallbackProcess)...
class TestChildProcessCleanup (line 349) | class TestChildProcessCleanup:
method test_basic_child_process_cleanup (line 356) | async def test_basic_child_process_cleanup(self):
method test_nested_process_tree (line 380) | async def test_nested_process_tree(self):
method test_early_parent_exit (line 416) | async def test_early_parent_exit(self):
function test_stdio_client_graceful_stdin_exit (line 450) | async def test_stdio_client_graceful_stdin_exit():
function test_stdio_client_stdin_close_ignored (line 505) | async def test_stdio_client_stdin_close_ignored():
FILE: tests/client/test_transport_stream_cleanup.py
function _assert_no_memory_stream_leak (line 28) | def _assert_no_memory_stream_leak() -> Iterator[None]:
function test_sse_client_closes_all_streams_on_connection_error (line 60) | async def test_sse_client_closes_all_streams_on_connection_error(free_tc...
function test_sse_client_closes_all_streams_on_http_error (line 74) | async def test_sse_client_closes_all_streams_on_http_error() -> None:
function test_streamable_http_client_closes_all_streams_on_exit (line 97) | async def test_streamable_http_client_closes_all_streams_on_exit() -> None:
function test_websocket_client_closes_all_streams_on_connection_error (line 110) | async def test_websocket_client_closes_all_streams_on_connection_error(f...
FILE: tests/client/transports/test_memory.py
function simple_server (line 13) | def simple_server() -> Server:
function mcpserver_server (line 33) | def mcpserver_server() -> MCPServer:
function test_with_server (line 53) | async def test_with_server(simple_server: Server):
function test_with_mcpserver (line 61) | async def test_with_mcpserver(mcpserver_server: MCPServer):
function test_server_is_running (line 69) | async def test_server_is_running(mcpserver_server: MCPServer):
function test_list_tools (line 75) | async def test_list_tools(mcpserver_server: MCPServer):
function test_call_tool (line 84) | async def test_call_tool(mcpserver_server: MCPServer):
function test_raise_exceptions (line 93) | async def test_raise_exceptions(mcpserver_server: MCPServer):
FILE: tests/conftest.py
function anyio_backend (line 5) | def anyio_backend():
FILE: tests/experimental/tasks/client/test_capabilities.py
function test_client_capabilities_without_tasks (line 24) | async def test_client_capabilities_without_tasks():
function test_client_capabilities_with_tasks (line 81) | async def test_client_capabilities_with_tasks():
function test_client_capabilities_auto_built_from_handlers (line 161) | async def test_client_capabilities_auto_built_from_handlers():
function test_client_capabilities_with_task_augmented_handlers (line 242) | async def test_client_capabilities_with_task_augmented_handlers():
FILE: tests/experimental/tasks/client/test_handlers.py
class ClientTestStreams (line 63) | class ClientTestStreams:
function client_streams (line 73) | async def client_streams() -> AsyncIterator[ClientTestStreams]:
function _default_message_handler (line 101) | async def _default_message_handler(
function test_client_handles_get_task_request (line 109) | async def test_client_handles_get_task_request(client_streams: ClientTes...
function test_client_handles_get_task_result_request (line 173) | async def test_client_handles_get_task_result_request(client_streams: Cl...
function test_client_handles_list_tasks_request (line 236) | async def test_client_handles_list_tasks_request(client_streams: ClientT...
function test_client_handles_cancel_task_request (line 291) | async def test_client_handles_cancel_task_request(client_streams: Client...
function test_client_task_augmented_sampling (line 355) | async def test_client_task_augmented_sampling(client_streams: ClientTest...
function test_client_task_augmented_elicitation (line 499) | async def test_client_task_augmented_elicitation(client_streams: ClientT...
function test_client_returns_error_for_unhandled_task_request (line 641) | async def test_client_returns_error_for_unhandled_task_request(client_st...
function test_client_returns_error_for_unhandled_task_result_request (line 680) | async def test_client_returns_error_for_unhandled_task_result_request(cl...
function test_client_returns_error_for_unhandled_list_tasks_request (line 716) | async def test_client_returns_error_for_unhandled_list_tasks_request(cli...
function test_client_returns_error_for_unhandled_cancel_task_request (line 752) | async def test_client_returns_error_for_unhandled_cancel_task_request(cl...
function test_client_returns_error_for_unhandled_task_augmented_sampling (line 788) | async def test_client_returns_error_for_unhandled_task_augmented_samplin...
function test_client_returns_error_for_unhandled_task_augmented_elicitation (line 832) | async def test_client_returns_error_for_unhandled_task_augmented_elicita...
FILE: tests/experimental/tasks/client/test_poll_task.py
function make_task_result (line 14) | def make_task_result(
function make_status_sequence (line 33) | def make_status_sequence(
function mock_session (line 47) | def mock_session() -> AsyncMock:
function features (line 52) | def features(mock_session: AsyncMock) -> ExperimentalClientFeatures:
function test_poll_task_yields_until_completed (line 57) | async def test_poll_task_yields_until_completed(features: ExperimentalCl...
function test_poll_task_exits_on_terminal (line 68) | async def test_poll_task_exits_on_terminal(features: ExperimentalClientF...
function test_poll_task_continues_through_input_required (line 78) | async def test_poll_task_continues_through_input_required(features: Expe...
function test_poll_task_passes_task_id (line 88) | async def test_poll_task_passes_task_id(features: ExperimentalClientFeat...
function test_poll_task_yields_full_result (line 104) | async def test_poll_task_yields_full_result(features: ExperimentalClient...
FILE: tests/experimental/tasks/client/test_tasks.py
class AppContext (line 38) | class AppContext:
function _handle_list_tools (line 46) | async def _handle_list_tools(
function _handle_call_tool_with_done_event (line 52) | async def _handle_call_tool_with_done_event(
function _make_lifespan (line 75) | def _make_lifespan(store: InMemoryTaskStore, task_done_events: dict[str,...
function test_session_experimental_get_task (line 84) | async def test_session_experimental_get_task() -> None:
function test_session_experimental_get_task_result (line 135) | async def test_session_experimental_get_task_result() -> None:
function test_session_experimental_list_tasks (line 188) | async def test_session_experimental_list_tasks() -> None:
function test_session_experimental_cancel_task (line 230) | async def test_session_experimental_cancel_task() -> None:
FILE: tests/experimental/tasks/server/test_context.py
function test_task_context_properties (line 12) | async def test_task_context_properties() -> None:
function test_task_context_update_status (line 27) | async def test_task_context_update_status() -> None:
function test_task_context_complete (line 44) | async def test_task_context_complete() -> None:
function test_task_context_fail (line 66) | async def test_task_context_fail() -> None:
function test_task_context_cancellation (line 84) | async def test_task_context_cancellation() -> None:
function test_create_task_state_generates_id (line 99) | def test_create_task_state_generates_id() -> None:
function test_create_task_state_uses_provided_id (line 107) | def test_create_task_state_uses_provided_id() -> None:
function test_create_task_state_null_ttl (line 113) | def test_create_task_state_null_ttl() -> None:
function test_create_task_state_has_created_at (line 119) | def test_create_task_state_has_created_at() -> None:
function test_task_execution_provides_context (line 126) | async def test_task_execution_provides_context() -> None:
function test_task_execution_auto_fails_on_exception (line 139) | async def test_task_execution_auto_fails_on_exception() -> None:
function test_task_execution_doesnt_fail_if_already_terminal (line 157) | async def test_task_execution_doesnt_fail_if_already_terminal() -> None:
function test_task_execution_not_found (line 177) | async def test_task_execution_not_found() -> None:
FILE: tests/experimental/tasks/server/test_integration.py
class AppContext (line 44) | class AppContext:
function _make_lifespan (line 52) | def _make_lifespan(store: InMemoryTaskStore, task_done_events: dict[str,...
function test_task_lifecycle_with_task_execution (line 61) | async def test_task_lifecycle_with_task_execution() -> None:
function test_task_auto_fails_on_exception (line 169) | async def test_task_auto_fails_on_exception() -> None:
FILE: tests/experimental/tasks/server/test_run_task_flow.py
function _handle_list_tools_simple_task (line 40) | async def _handle_list_tools_simple_task(
function test_run_task_basic_flow (line 46) | async def test_run_task_basic_flow() -> None:
function test_run_task_auto_fails_on_exception (line 97) | async def test_run_task_auto_fails_on_exception() -> None:
function test_enable_tasks_auto_registers_handlers (line 138) | async def test_enable_tasks_auto_registers_handlers() -> None:
function test_enable_tasks_with_custom_store_and_queue (line 159) | async def test_enable_tasks_with_custom_store_and_queue() -> None:
function test_enable_tasks_skips_default_handlers_when_custom_registered (line 172) | async def test_enable_tasks_skips_default_handlers_when_custom_registere...
function test_run_task_without_enable_tasks_raises (line 189) | async def test_run_task_without_enable_tasks_raises() -> None:
function test_task_support_task_group_before_run_raises (line 205) | async def test_task_support_task_group_before_run_raises() -> None:
function test_run_task_without_session_raises (line 213) | async def test_run_task_without_session_raises() -> None:
function test_run_task_without_task_metadata_raises (line 231) | async def test_run_task_without_task_metadata_raises() -> None:
function test_run_task_with_model_immediate_response (line 250) | async def test_run_task_with_model_immediate_response() -> None:
function test_run_task_doesnt_complete_if_already_terminal (line 287) | async def test_run_task_doesnt_complete_if_already_terminal() -> None:
function test_run_task_doesnt_fail_if_already_terminal (line 328) | async def test_run_task_doesnt_fail_if_already_terminal() -> None:
FILE: tests/experimental/tasks/server/test_server.py
function test_list_tasks_handler (line 56) | async def test_list_tasks_handler() -> None:
function test_get_task_handler (line 77) | async def test_get_task_handler() -> None:
function test_get_task_result_handler (line 100) | async def test_get_task_result_handler() -> None:
function test_cancel_task_handler (line 119) | async def test_cancel_task_handler() -> None:
function test_server_capabilities_include_tasks (line 141) | async def test_server_capabilities_include_tasks() -> None:
function test_server_capabilities_partial_tasks (line 167) | async def test_server_capabilities_partial_tasks() -> None: # pragma: n...
function test_tool_with_task_execution_metadata (line 184) | async def test_tool_with_task_execution_metadata() -> None:
function test_task_metadata_in_call_tool_request (line 225) | async def test_task_metadata_in_call_tool_request() -> None:
function test_task_metadata_is_task_property (line 256) | async def test_task_metadata_is_task_property() -> None:
function test_update_capabilities_no_handlers (line 289) | async def test_update_capabilities_no_handlers() -> None:
function test_update_capabilities_partial_handlers (line 298) | async def test_update_capabilities_partial_handlers() -> None:
function test_default_task_handlers_via_enable_tasks (line 317) | async def test_default_task_handlers_via_enable_tasks() -> None:
function test_build_elicit_form_request (line 400) | async def test_build_elicit_form_request() -> None:
function test_build_elicit_url_request (line 441) | async def test_build_elicit_url_request() -> None:
function test_build_create_message_request (line 487) | async def test_build_create_message_request() -> None:
function test_send_message (line 538) | async def test_send_message() -> None:
function test_response_routing_success (line 575) | async def test_response_routing_success() -> None:
function test_response_routing_error (line 629) | async def test_response_routing_error() -> None:
function test_response_routing_skips_non_matching_routers (line 684) | async def test_response_routing_skips_non_matching_routers() -> None:
function test_error_routing_skips_non_matching_routers (line 742) | async def test_error_routing_skips_non_matching_routers() -> None:
FILE: tests/experimental/tasks/server/test_server_task_context.py
function test_server_task_context_properties (line 33) | async def test_server_task_context_properties() -> None:
function test_server_task_context_request_cancellation (line 55) | async def test_server_task_context_request_cancellation() -> None:
function test_server_task_context_update_status_with_notify (line 77) | async def test_server_task_context_update_status_with_notify() -> None:
function test_server_task_context_update_status_without_notify (line 99) | async def test_server_task_context_update_status_without_notify() -> None:
function test_server_task_context_complete_with_notify (line 121) | async def test_server_task_context_complete_with_notify() -> None:
function test_server_task_context_fail_with_notify (line 144) | async def test_server_task_context_fail_with_notify() -> None:
function test_elicit_raises_when_client_lacks_capability (line 166) | async def test_elicit_raises_when_client_lacks_capability() -> None:
function test_create_message_raises_when_client_lacks_capability (line 192) | async def test_create_message_raises_when_client_lacks_capability() -> N...
function test_elicit_raises_without_handler (line 218) | async def test_elicit_raises_without_handler() -> None:
function test_elicit_url_raises_without_handler (line 241) | async def test_elicit_url_raises_without_handler() -> None:
function test_create_message_raises_without_handler (line 268) | async def test_create_message_raises_without_handler() -> None:
function test_elicit_queues_request_and_waits_for_response (line 291) | async def test_elicit_queues_request_and_waits_for_response() -> None:
function test_elicit_url_queues_request_and_waits_for_response (line 359) | async def test_elicit_url_queues_request_and_waits_for_response() -> None:
function test_create_message_queues_request_and_waits_for_response (line 427) | async def test_create_message_queues_request_and_waits_for_response() ->...
function test_elicit_restores_status_on_cancellation (line 502) | async def test_elicit_restores_status_on_cancellation() -> None:
function test_create_message_restores_status_on_cancellation (line 571) | async def test_create_message_restores_status_on_cancellation() -> None:
function test_elicit_as_task_raises_without_handler (line 640) | async def test_elicit_as_task_raises_without_handler() -> None:
function test_create_message_as_task_raises_without_handler (line 675) | async def test_create_message_as_task_raises_without_handler() -> None:
FILE: tests/experimental/tasks/server/test_store.py
function store (line 15) | async def store() -> AsyncIterator[InMemoryTaskStore]:
function test_create_and_get (line 23) | async def test_create_and_get(store: InMemoryTaskStore) -> None:
function test_create_with_custom_id (line 38) | async def test_create_with_custom_id(store: InMemoryTaskStore) -> None:
function test_create_duplicate_id_raises (line 54) | async def test_create_duplicate_id_raises(store: InMemoryTaskStore) -> N...
function test_get_nonexistent_returns_none (line 63) | async def test_get_nonexistent_returns_none(store: InMemoryTaskStore) ->...
function test_update_status (line 70) | async def test_update_status(store: InMemoryTaskStore) -> None:
function test_update_nonexistent_raises (line 86) | async def test_update_nonexistent_raises(store: InMemoryTaskStore) -> None:
function test_store_and_get_result (line 93) | async def test_store_and_get_result(store: InMemoryTaskStore) -> None:
function test_get_result_nonexistent_returns_none (line 107) | async def test_get_result_nonexistent_returns_none(store: InMemoryTaskSt...
function test_get_result_no_result_returns_none (line 114) | async def test_get_result_no_result_returns_none(store: InMemoryTaskStor...
function test_list_tasks (line 122) | async def test_list_tasks(store: InMemoryTaskStore) -> None:
function test_list_tasks_pagination (line 134) | async def test_list_tasks_pagination() -> None:
function test_list_tasks_invalid_cursor (line 162) | async def test_list_tasks_invalid_cursor(store: InMemoryTaskStore) -> None:
function test_delete_task (line 171) | async def test_delete_task(store: InMemoryTaskStore) -> None:
function test_get_all_tasks_helper (line 187) | async def test_get_all_tasks_helper(store: InMemoryTaskStore) -> None:
function test_store_result_nonexistent_raises (line 197) | async def test_store_result_nonexistent_raises(store: InMemoryTaskStore)...
function test_create_task_with_null_ttl (line 206) | async def test_create_task_with_null_ttl(store: InMemoryTaskStore) -> None:
function test_task_expiration_cleanup (line 218) | async def test_task_expiration_cleanup(store: InMemoryTaskStore) -> None:
function test_task_with_null_ttl_never_expires (line 241) | async def test_task_with_null_ttl_never_expires(store: InMemoryTaskStore...
function test_terminal_task_ttl_reset (line 262) | async def test_terminal_task_ttl_reset(store: InMemoryTaskStore) -> None:
function test_terminal_status_transition_rejected (line 283) | async def test_terminal_status_transition_rejected(store: InMemoryTaskSt...
function test_terminal_status_allows_same_status (line 307) | async def test_terminal_status_allows_same_status(store: InMemoryTaskSto...
function test_wait_for_update_nonexistent_raises (line 325) | async def test_wait_for_update_nonexistent_raises(store: InMemoryTaskSto...
function test_cancel_task_succeeds_for_working_task (line 332) | async def test_cancel_task_succeeds_for_working_task(store: InMemoryTask...
function test_cancel_task_rejects_nonexistent_task (line 349) | async def test_cancel_task_rejects_nonexistent_task(store: InMemoryTaskS...
function test_cancel_task_rejects_completed_task (line 359) | async def test_cancel_task_rejects_completed_task(store: InMemoryTaskSto...
function test_cancel_task_rejects_failed_task (line 372) | async def test_cancel_task_rejects_failed_task(store: InMemoryTaskStore)...
function test_cancel_task_rejects_already_cancelled_task (line 385) | async def test_cancel_task_rejects_already_cancelled_task(store: InMemor...
function test_cancel_task_succeeds_for_input_required_task (line 398) | async def test_cancel_task_succeeds_for_input_required_task(store: InMem...
FILE: tests/experimental/tasks/server/test_task_result_handler.py
function store (line 30) | async def store() -> AsyncIterator[InMemoryTaskStore]:
function queue (line 38) | def queue() -> InMemoryTaskMessageQueue:
function handler (line 44) | def handler(store: InMemoryTaskStore, queue: InMemoryTaskMessageQueue) -...
function test_handle_returns_result_for_completed_task (line 50) | async def test_handle_returns_result_for_completed_task(
function test_handle_raises_for_nonexistent_task (line 71) | async def test_handle_raises_for_nonexistent_task(
function test_handle_returns_empty_result_when_no_result_stored (line 85) | async def test_handle_returns_empty_result_when_no_result_stored(
function test_handle_delivers_queued_messages (line 104) | async def test_handle_delivers_queued_messages(
function test_handle_waits_for_task_completion (line 137) | async def test_handle_waits_for_task_completion(
function test_route_response_resolves_pending_request (line 166) | async def test_route_response_resolves_pending_request(
function test_route_response_returns_false_for_unknown_request (line 181) | async def test_route_response_returns_false_for_unknown_request(
function test_route_response_returns_false_for_already_done_resolver (line 190) | async def test_route_response_returns_false_for_already_done_resolver(
function test_route_error_resolves_pending_request_with_exception (line 204) | async def test_route_error_resolves_pending_request_with_exception(
function test_route_error_returns_false_for_unknown_request (line 223) | async def test_route_error_returns_false_for_unknown_request(
function test_deliver_registers_resolver_for_request_messages (line 233) | async def test_deliver_registers_resolver_for_request_messages(
function test_deliver_skips_resolver_registration_when_no_original_id (line 263) | async def test_deliver_skips_resolver_registration_when_no_original_id(
function test_wait_for_task_update_handles_store_exception (line 295) | async def test_wait_for_task_update_handles_store_exception(
function test_wait_for_task_update_handles_queue_exception (line 332) | async def test_wait_for_task_update_handles_queue_exception(
FILE: tests/experimental/tasks/test_capabilities.py
class TestCheckTasksCapability (line 24) | class TestCheckTasksCapability:
method test_required_requests_none_returns_true (line 27) | def test_required_requests_none_returns_true(self) -> None:
method test_client_requests_none_returns_false (line 33) | def test_client_requests_none_returns_false(self) -> None:
method test_elicitation_required_but_client_missing (line 39) | def test_elicitation_required_but_client_missing(self) -> None:
method test_elicitation_create_required_but_client_missing (line 47) | def test_elicitation_create_required_but_client_missing(self) -> None:
method test_elicitation_create_present (line 61) | def test_elicitation_create_present(self) -> None:
method test_sampling_required_but_client_missing (line 75) | def test_sampling_required_but_client_missing(self) -> None:
method test_sampling_create_message_required_but_client_missing (line 81) | def test_sampling_create_message_required_but_client_missing(self) -> ...
method test_sampling_create_message_present (line 95) | def test_sampling_create_message_present(self) -> None:
method test_both_elicitation_and_sampling_present (line 109) | def test_both_elicitation_and_sampling_present(self) -> None:
method test_elicitation_without_create_required (line 125) | def test_elicitation_without_create_required(self) -> None:
method test_sampling_without_create_message_required (line 139) | def test_sampling_without_create_message_required(self) -> None:
class TestHasTaskAugmentedElicitation (line 154) | class TestHasTaskAugmentedElicitation:
method test_tasks_none (line 157) | def test_tasks_none(self) -> None:
method test_requests_none (line 162) | def test_requests_none(self) -> None:
method test_elicitation_none (line 167) | def test_elicitation_none(self) -> None:
method test_create_none (line 172) | def test_create_none(self) -> None:
method test_create_present (line 181) | def test_create_present(self) -> None:
class TestHasTaskAugmentedSampling (line 193) | class TestHasTaskAugmentedSampling:
method test_tasks_none (line 196) | def test_tasks_none(self) -> None:
method test_requests_none (line 201) | def test_requests_none(self) -> None:
method test_sampling_none (line 206) | def test_sampling_none(self) -> None:
method test_create_message_none (line 211) | def test_create_message_none(self) -> None:
method test_create_message_present (line 218) | def test_create_message_present(self) -> None:
class TestRequireTaskAugmentedElicitation (line 230) | class TestRequireTaskAugmentedElicitation:
method test_raises_when_none (line 233) | def test_raises_when_none(self) -> None:
method test_raises_when_missing (line 239) | def test_raises_when_missing(self) -> None:
method test_passes_when_present (line 246) | def test_passes_when_present(self) -> None:
class TestRequireTaskAugmentedSampling (line 258) | class TestRequireTaskAugmentedSampling:
method test_raises_when_none (line 261) | def test_raises_when_none(self) -> None:
method test_raises_when_missing (line 267) | def test_raises_when_missing(self) -> None:
method test_passes_when_present (line 274) | def test_passes_when_present(self) -> None:
FILE: tests/experimental/tasks/test_elicitation_scenarios.py
function create_client_task_handlers (line 48) | def create_client_task_handlers(
function create_sampling_task_handlers (line 112) | def create_sampling_task_handlers(
function test_scenario1_normal_tool_normal_elicitation (line 181) | async def test_scenario1_normal_tool_normal_elicitation() -> None:
function test_scenario2_normal_tool_task_augmented_elicitation (line 260) | async def test_scenario2_normal_tool_task_augmented_elicitation() -> None:
function test_scenario3_task_augmented_tool_normal_elicitation (line 338) | async def test_scenario3_task_augmented_tool_normal_elicitation() -> None:
function test_scenario4_task_augmented_tool_task_augmented_elicitation (line 429) | async def test_scenario4_task_augmented_tool_task_augmented_elicitation(...
function test_scenario2_sampling_normal_tool_task_augmented_sampling (line 528) | async def test_scenario2_sampling_normal_tool_task_augmented_sampling() ...
function test_scenario4_sampling_task_augmented_tool_task_augmented_sampling (line 608) | async def test_scenario4_sampling_task_augmented_tool_task_augmented_sam...
FILE: tests/experimental/tasks/test_message_queue.py
function queue (line 15) | def queue() -> InMemoryTaskMessageQueue:
function make_request (line 19) | def make_request(id: int = 1, method: str = "test/method") -> JSONRPCReq...
function make_notification (line 23) | def make_notification(method: str = "test/notify") -> JSONRPCNotification:
class TestInMemoryTaskMessageQueue (line 27) | class TestInMemoryTaskMessageQueue:
method test_enqueue_and_dequeue (line 29) | async def test_enqueue_and_dequeue(self, queue: InMemoryTaskMessageQue...
method test_dequeue_empty_returns_none (line 42) | async def test_dequeue_empty_returns_none(self, queue: InMemoryTaskMes...
method test_fifo_ordering (line 48) | async def test_fifo_ordering(self, queue: InMemoryTaskMessageQueue) ->...
method test_separate_queues_per_task (line 65) | async def test_separate_queues_per_task(self, queue: InMemoryTaskMessa...
method test_peek_does_not_remove (line 77) | async def test_peek_does_not_remove(self, queue: InMemoryTaskMessageQu...
method test_is_empty (line 92) | async def test_is_empty(self, queue: InMemoryTaskMessageQueue) -> None:
method test_clear_returns_all_messages (line 105) | async def test_clear_returns_all_messages(self, queue: InMemoryTaskMes...
method test_clear_empty_queue (line 119) | async def test_clear_empty_queue(self, queue: InMemoryTaskMessageQueue...
method test_notification_messages (line 125) | async def test_notification_messages(self, queue: InMemoryTaskMessageQ...
method test_message_timestamp (line 138) | async def test_message_timestamp(self, queue: InMemoryTaskMessageQueue...
method test_message_with_resolver (line 147) | async def test_message_with_resolver(self, queue: InMemoryTaskMessageQ...
method test_cleanup_specific_task (line 167) | async def test_cleanup_specific_task(self, queue: InMemoryTaskMessageQ...
method test_cleanup_all (line 178) | async def test_cleanup_all(self, queue: InMemoryTaskMessageQueue) -> N...
method test_wait_for_message_returns_immediately_if_message_exists (line 189) | async def test_wait_for_message_returns_immediately_if_message_exists(
method test_wait_for_message_blocks_until_message (line 201) | async def test_wait_for_message_blocks_until_message(self, queue: InMe...
method test_notify_message_available_wakes_waiter (line 226) | async def test_notify_message_available_wakes_waiter(self, queue: InMe...
method test_peek_empty_queue_returns_none (line 251) | async def test_peek_empty_queue_returns_none(self, queue: InMemoryTask...
method test_wait_for_message_double_check_race_condition (line 257) | async def test_wait_for_message_double_check_race_condition(self, queu...
class TestResolver (line 284) | class TestResolver:
method test_set_result_and_wait (line 286) | async def test_set_result_and_wait(self) -> None:
method test_set_exception_and_wait (line 297) | async def test_set_exception_and_wait(self) -> None:
method test_set_result_when_already_completed_raises (line 309) | async def test_set_result_when_already_completed_raises(self) -> None:
method test_set_exception_when_already_completed_raises (line 318) | async def test_set_exception_when_already_completed_raises(self) -> None:
method test_done_returns_false_before_completion (line 327) | async def test_done_returns_false_before_completion(self) -> None:
FILE: tests/experimental/tasks/test_request_context.py
function test_is_task_true_when_metadata_present (line 20) | def test_is_task_true_when_metadata_present() -> None:
function test_is_task_false_when_no_metadata (line 25) | def test_is_task_false_when_no_metadata() -> None:
function test_client_supports_tasks_true (line 30) | def test_client_supports_tasks_true() -> None:
function test_client_supports_tasks_false_no_tasks (line 35) | def test_client_supports_tasks_false_no_tasks() -> None:
function test_client_supports_tasks_false_no_capabilities (line 40) | def test_client_supports_tasks_false_no_capabilities() -> None:
function test_validate_task_mode_required_with_task_is_valid (line 45) | def test_validate_task_mode_required_with_task_is_valid() -> None:
function test_validate_task_mode_required_without_task_returns_error (line 51) | def test_validate_task_mode_required_without_task_returns_error() -> None:
function test_validate_task_mode_required_without_task_raises_by_default (line 59) | def test_validate_task_mode_required_without_task_raises_by_default() ->...
function test_validate_task_mode_forbidden_without_task_is_valid (line 66) | def test_validate_task_mode_forbidden_without_task_is_valid() -> None:
function test_validate_task_mode_forbidden_with_task_returns_error (line 72) | def test_validate_task_mode_forbidden_with_task_returns_error() -> None:
function test_validate_task_mode_forbidden_with_task_raises_by_default (line 80) | def test_validate_task_mode_forbidden_with_task_raises_by_default() -> N...
function test_validate_task_mode_none_treated_as_forbidden (line 87) | def test_validate_task_mode_none_treated_as_forbidden() -> None:
function test_validate_task_mode_optional_with_task_is_valid (line 94) | def test_validate_task_mode_optional_with_task_is_valid() -> None:
function test_validate_task_mode_optional_without_task_is_valid (line 100) | def test_validate_task_mode_optional_without_task_is_valid() -> None:
function test_validate_for_tool_with_execution_required (line 106) | def test_validate_for_tool_with_execution_required() -> None:
function test_validate_for_tool_without_execution (line 119) | def test_validate_for_tool_without_execution() -> None:
function test_validate_for_tool_optional_with_task (line 132) | def test_validate_for_tool_optional_with_task() -> None:
function test_can_use_tool_required_with_task_support (line 144) | def test_can_use_tool_required_with_task_support() -> None:
function test_can_use_tool_required_without_task_support (line 149) | def test_can_use_tool_required_without_task_support() -> None:
function test_can_use_tool_optional_without_task_support (line 154) | def test_can_use_tool_optional_without_task_support() -> None:
function test_can_use_tool_forbidden_without_task_support (line 159) | def test_can_use_tool_forbidden_without_task_support() -> None:
function test_can_use_tool_none_without_task_support (line 164) | def test_can_use_tool_none_without_task_support() -> None:
FILE: tests/experimental/tasks/test_spec_compliance.py
function _get_capabilities (line 32) | def _get_capabilities(server: Server) -> ServerCapabilities:
function test_server_without_task_handlers_has_no_tasks_capability (line 40) | def test_server_without_task_handlers_has_no_tasks_capability() -> None:
function _noop_get_task (line 47) | async def _noop_get_task(ctx: ServerRequestContext, params: GetTaskReque...
function _noop_list_tasks (line 51) | async def _noop_list_tasks(ctx: ServerRequestContext, params: PaginatedR...
function _noop_cancel_task (line 55) | async def _noop_cancel_task(ctx: ServerRequestContext, params: CancelTas...
function test_server_with_list_tasks_handler_declares_list_capability (line 59) | def test_server_with_list_tasks_handler_declares_list_capability() -> None:
function test_server_with_cancel_task_handler_declares_cancel_capability (line 69) | def test_server_with_cancel_task_handler_declares_cancel_capability() ->...
function test_server_with_get_task_handler_declares_requests_tools_call_capability (line 79) | def test_server_with_get_task_handler_declares_requests_tools_call_capab...
function test_server_without_list_handler_has_no_list_capability (line 97) | def test_server_without_list_handler_has_no_list_capability() -> None: ...
function test_server_without_cancel_handler_has_no_cancel_capability (line 112) | def test_server_without_cancel_handler_has_no_cancel_capability() -> Non...
function test_server_with_all_task_handlers_has_full_capability (line 122) | def test_server_with_all_task_handlers_has_full_capability() -> None:
class TestClientCapabilities (line 139) | class TestClientCapabilities:
method test_client_declares_tasks_capability (line 147) | def test_client_declares_tasks_capability(self) -> None:
class TestToolLevelNegotiation (line 152) | class TestToolLevelNegotiation:
method test_tool_execution_task_forbidden_rejects_task_augmented_call (line 159) | def test_tool_execution_task_forbidden_rejects_task_augmented_call(sel...
method test_tool_execution_task_absent_rejects_task_augmented_call (line 163) | def test_tool_execution_task_absent_rejects_task_augmented_call(self) ...
method test_tool_execution_task_optional_accepts_normal_call (line 167) | def test_tool_execution_task_optional_accepts_normal_call(self) -> None:
method test_tool_execution_task_optional_accepts_task_augmented_call (line 171) | def test_tool_execution_task_optional_accepts_task_augmented_call(self...
method test_tool_execution_task_required_rejects_normal_call (line 175) | def test_tool_execution_task_required_rejects_normal_call(self) -> None:
method test_tool_execution_task_required_accepts_task_augmented_call (line 179) | def test_tool_execution_task_required_accepts_task_augmented_call(self...
class TestCapabilityNegotiation (line 184) | class TestCapabilityNegotiation:
method test_receiver_without_capability_ignores_task_metadata (line 193) | def test_receiver_without_capability_ignores_task_metadata(self) -> None:
method test_receiver_with_capability_may_require_task_augmentation (line 199) | def test_receiver_with_capability_may_require_task_augmentation(self) ...
class TestTaskStatusLifecycle (line 206) | class TestTaskStatusLifecycle:
method test_task_begins_in_working_status (line 218) | def test_task_begins_in_working_status(self) -> None:
method test_working_to_completed_transition (line 222) | def test_working_to_completed_transition(self) -> None:
method test_working_to_failed_transition (line 226) | def test_working_to_failed_transition(self) -> None:
method test_working_to_cancelled_transition (line 230) | def test_working_to_cancelled_transition(self) -> None:
method test_working_to_input_required_transition (line 234) | def test_working_to_input_required_transition(self) -> None:
method test_input_required_to_working_transition (line 238) | def test_input_required_to_working_transition(self) -> None:
method test_input_required_to_terminal_transition (line 242) | def test_input_required_to_terminal_transition(self) -> None:
method test_terminal_state_no_further_transitions (line 246) | def test_terminal_state_no_further_transitions(self) -> None:
method test_completed_is_terminal (line 250) | def test_completed_is_terminal(self) -> None:
method test_failed_is_terminal (line 254) | def test_failed_is_terminal(self) -> None:
method test_cancelled_is_terminal (line 258) | def test_cancelled_is_terminal(self) -> None:
class TestInputRequiredStatus (line 263) | class TestInputRequiredStatus:
method test_input_required_status_retrievable_via_tasks_get (line 269) | def test_input_required_status_retrievable_via_tasks_get(self) -> None:
method test_input_required_related_task_metadata_in_requests (line 273) | def test_input_required_related_task_metadata_in_requests(self) -> None:
class TestCreatingTask (line 280) | class TestCreatingTask:
method test_task_augmented_request_returns_create_task_result (line 290) | def test_task_augmented_request_returns_create_task_result(self) -> None:
method test_create_task_result_contains_task_id (line 294) | def test_create_task_result_contains_task_id(self) -> None:
method test_create_task_result_contains_status_working (line 298) | def test_create_task_result_contains_status_working(self) -> None:
method test_create_task_result_contains_created_at (line 302) | def test_create_task_result_contains_created_at(self) -> None:
method test_create_task_result_created_at_is_iso8601 (line 306) | def test_create_task_result_created_at_is_iso8601(self) -> None:
method test_create_task_result_may_contain_ttl (line 310) | def test_create_task_result_may_contain_ttl(self) -> None:
method test_create_task_result_may_contain_poll_interval (line 314) | def test_create_task_result_may_contain_poll_interval(self) -> None:
method test_create_task_result_may_contain_status_message (line 318) | def test_create_task_result_may_contain_status_message(self) -> None:
method test_receiver_may_override_requested_ttl (line 322) | def test_receiver_may_override_requested_ttl(self) -> None:
method test_model_immediate_response_in_meta (line 326) | def test_model_immediate_response_in_meta(self) -> None:
class TestGettingTaskStatus (line 360) | class TestGettingTaskStatus:
method test_tasks_get_returns_task_object (line 365) | def test_tasks_get_returns_task_object(self) -> None:
method test_tasks_get_returns_current_status (line 369) | def test_tasks_get_returns_current_status(self) -> None:
method test_tasks_get_may_return_poll_interval (line 373) | def test_tasks_get_may_return_poll_interval(self) -> None:
method test_tasks_get_invalid_task_id_returns_error (line 377) | def test_tasks_get_invalid_task_id_returns_error(self) -> None:
method test_tasks_get_nonexistent_task_id_returns_error (line 381) | def test_tasks_get_nonexistent_task_id_returns_error(self) -> None:
class TestRetrievingResults (line 386) | class TestRetrievingResults:
method test_tasks_result_returns_underlying_result (line 393) | def test_tasks_result_returns_underlying_result(self) -> None:
method test_tasks_result_blocks_until_terminal (line 397) | def test_tasks_result_blocks_until_terminal(self) -> None:
method test_tasks_result_unblocks_on_terminal (line 401) | def test_tasks_result_unblocks_on_terminal(self) -> None:
method test_tasks_result_includes_related_task_metadata (line 405) | def test_tasks_result_includes_related_task_metadata(self) -> None:
method test_tasks_result_returns_error_for_failed_task (line 409) | def test_tasks_result_returns_error_for_failed_task(self) -> None:
method test_tasks_result_invalid_task_id_returns_error (line 415) | def test_tasks_result_invalid_task_id_returns_error(self) -> None:
class TestListingTasks (line 420) | class TestListingTasks:
method test_tasks_list_returns_array_of_tasks (line 425) | def test_tasks_list_returns_array_of_tasks(self) -> None:
method test_tasks_list_pagination_with_cursor (line 429) | def test_tasks_list_pagination_with_cursor(self) -> None:
method test_tasks_list_returns_next_cursor_when_more_results (line 433) | def test_tasks_list_returns_next_cursor_when_more_results(self) -> None:
method test_tasks_list_cursors_are_opaque (line 437) | def test_tasks_list_cursors_are_opaque(self) -> None:
method test_tasks_list_invalid_cursor_returns_error (line 441) | def test_tasks_list_invalid_cursor_returns_error(self) -> None:
class TestCancellingTasks (line 446) | class TestCancellingTasks:
method test_tasks_cancel_returns_cancelled_task (line 451) | def test_tasks_cancel_returns_cancelled_task(self) -> None:
method test_tasks_cancel_terminal_task_returns_error (line 455) | def test_tasks_cancel_terminal_task_returns_error(self) -> None:
method test_tasks_cancel_completed_task_returns_error (line 459) | def test_tasks_cancel_completed_task_returns_error(self) -> None:
method test_tasks_cancel_failed_task_returns_error (line 463) | def test_tasks_cancel_failed_task_returns_error(self) -> None:
method test_tasks_cancel_already_cancelled_task_returns_error (line 467) | def test_tasks_cancel_already_cancelled_task_returns_error(self) -> None:
method test_tasks_cancel_invalid_task_id_returns_error (line 471) | def test_tasks_cancel_invalid_task_id_returns_error(self) -> None:
class TestStatusNotifications (line 476) | class TestStatusNotifications:
method test_receiver_may_send_status_notification (line 481) | def test_receiver_may_send_status_notification(self) -> None:
method test_status_notification_contains_task_id (line 485) | def test_status_notification_contains_task_id(self) -> None:
method test_status_notification_contains_status (line 489) | def test_status_notification_contains_status(self) -> None:
class TestTaskManagement (line 494) | class TestTaskManagement:
method test_task_ids_are_unique_strings (line 504) | def test_task_ids_are_unique_strings(self) -> None:
method test_multiple_tasks_have_unique_ids (line 508) | def test_multiple_tasks_have_unique_ids(self) -> None:
method test_receiver_may_delete_tasks_after_ttl (line 512) | def test_receiver_may_delete_tasks_after_ttl(self) -> None:
method test_related_task_metadata_in_task_messages (line 516) | def test_related_task_metadata_in_task_messages(self) -> None:
method test_tasks_get_does_not_require_related_task_metadata (line 522) | def test_tasks_get_does_not_require_related_task_metadata(self) -> None:
method test_tasks_list_does_not_require_related_task_metadata (line 526) | def test_tasks_list_does_not_require_related_task_metadata(self) -> None:
method test_tasks_cancel_does_not_require_related_task_metadata (line 530) | def test_tasks_cancel_does_not_require_related_task_metadata(self) -> ...
class TestResultHandling (line 535) | class TestResultHandling:
method test_create_task_result_returned_immediately (line 541) | def test_create_task_result_returned_immediately(self) -> None:
method test_tasks_result_matches_underlying_result_structure (line 545) | def test_tasks_result_matches_underlying_result_structure(self) -> None:
method test_tasks_result_for_tool_call_returns_call_tool_result (line 549) | def test_tasks_result_for_tool_call_returns_call_tool_result(self) -> ...
class TestProgressTracking (line 554) | class TestProgressTracking:
method test_progress_token_valid_throughout_task_lifetime (line 559) | def test_progress_token_valid_throughout_task_lifetime(self) -> None:
method test_progress_notifications_sent_during_task_execution (line 563) | def test_progress_notifications_sent_during_task_execution(self) -> None:
class TestProtocolErrors (line 568) | class TestProtocolErrors:
method test_invalid_request_for_required_task_augmentation (line 575) | def test_invalid_request_for_required_task_augmentation(self) -> None:
method test_invalid_params_for_invalid_task_id (line 579) | def test_invalid_params_for_invalid_task_id(self) -> None:
method test_invalid_params_for_nonexistent_task_id (line 583) | def test_invalid_params_for_nonexistent_task_id(self) -> None:
method test_invalid_params_for_invalid_cursor (line 587) | def test_invalid_params_for_invalid_cursor(self) -> None:
method test_invalid_params_for_cancel_terminal_task (line 591) | def test_invalid_params_for_cancel_terminal_task(self) -> None:
method test_internal_error_for_server_failure (line 595) | def test_internal_error_for_server_failure(self) -> None:
class TestTaskExecutionErrors (line 600) | class TestTaskExecutionErrors:
method test_underlying_failure_moves_task_to_failed (line 607) | def test_underlying_failure_moves_task_to_failed(self) -> None:
method test_failed_task_has_status_message (line 611) | def test_failed_task_has_status_message(self) -> None:
method test_tasks_result_returns_underlying_error (line 615) | def test_tasks_result_returns_underlying_error(self) -> None:
method test_tool_call_is_error_true_moves_to_failed (line 619) | def test_tool_call_is_error_true_moves_to_failed(self) -> None:
class TestTaskObject (line 624) | class TestTaskObject:
method test_task_has_task_id_string (line 634) | def test_task_has_task_id_string(self) -> None:
method test_task_has_status (line 638) | def test_task_has_status(self) -> None:
method test_task_status_message_is_optional (line 642) | def test_task_status_message_is_optional(self) -> None:
method test_task_has_created_at (line 646) | def test_task_has_created_at(self) -> None:
method test_task_ttl_is_optional (line 650) | def test_task_ttl_is_optional(self) -> None:
method test_task_poll_interval_is_optional (line 654) | def test_task_poll_interval_is_optional(self) -> None:
class TestRelatedTaskMetadata (line 659) | class TestRelatedTaskMetadata:
method test_related_task_metadata_structure (line 664) | def test_related_task_metadata_structure(self) -> None:
method test_related_task_metadata_contains_task_id (line 668) | def test_related_task_metadata_contains_task_id(self) -> None:
class TestAccessAndIsolation (line 673) | class TestAccessAndIsolation:
method test_task_bound_to_authorization_context (line 679) | def test_task_bound_to_authorization_context(self) -> None:
method test_reject_task_operations_outside_authorization_context (line 683) | def test_reject_task_operations_outside_authorization_context(self) ->...
method test_non_authorized_environments_use_secure_ids (line 689) | def test_non_authorized_environments_use_secure_ids(self) -> None:
method test_non_authorized_environments_use_shorter_ttls (line 695) | def test_non_authorized_environments_use_shorter_ttls(self) -> None:
class TestResourceLimits (line 700) | class TestResourceLimits:
method test_concurrent_task_limit_enforced (line 707) | def test_concurrent_task_limit_enforced(self) -> None:
method test_maximum_ttl_constraint_enforced (line 711) | def test_maximum_ttl_constraint_enforced(self) -> None:
method test_expired_tasks_cleaned_up (line 715) | def test_expired_tasks_cleaned_up(self) -> None:
FILE: tests/issues/test_100_tool_listing.py
function test_list_tools_returns_all_tools (line 8) | async def test_list_tools_returns_all_tools():
FILE: tests/issues/test_1027_win_unreachable_cleanup.py
function test_lifespan_cleanup_executed (line 24) | async def test_lifespan_cleanup_executed():
function test_stdin_close_triggers_cleanup (line 124) | async def test_stdin_close_triggers_cleanup():
FILE: tests/issues/test_129_resource_templates.py
function test_resource_templates (line 8) | async def test_resource_templates():
FILE: tests/issues/test_1338_icons_and_metadata.py
function test_icons_and_website_url (line 11) | async def test_icons_and_website_url():
function test_multiple_icons (line 95) | async def test_multiple_icons():
function test_no_icons_or_website (line 122) | async def test_no_icons_or_website():
FILE: tests/issues/test_1363_race_condition_streamable_http.py
class RaceConditionTestServer (line 35) | class RaceConditionTestServer(Server):
method __init__ (line 36) | def __init__(self):
function create_app (line 40) | def create_app(json_response: bool = False) -> Starlette:
class ServerThread (line 64) | class ServerThread(threading.Thread):
method __init__ (line 67) | def __init__(self, app: Starlette):
method run (line 72) | def run(self) -> None:
method stop (line 87) | def stop(self) -> None:
function check_logs_for_race_condition_errors (line 92) | def check_logs_for_race_condition_errors(caplog: pytest.LogCaptureFixtur...
function test_race_condition_invalid_accept_headers (line 122) | async def test_race_condition_invalid_accept_headers(caplog: pytest.LogC...
function test_race_condition_invalid_content_type (line 196) | async def test_race_condition_invalid_content_type(caplog: pytest.LogCap...
function test_race_condition_message_router_async_for (line 236) | async def test_race_condition_message_router_async_for(caplog: pytest.Lo...
FILE: tests/issues/test_141_resource_templates.py
function test_resource_template_edge_cases (line 13) | async def test_resource_template_edge_cases():
function test_resource_template_client_interaction (line 66) | async def test_resource_template_client_interaction():
FILE: tests/issues/test_152_resource_mime_type.py
function test_mcpserver_resource_mime_type (line 20) | async def test_mcpserver_resource_mime_type():
function test_lowlevel_resource_mime_type (line 66) | async def test_lowlevel_resource_mime_type():
FILE: tests/issues/test_1574_resource_uri_validation.py
function test_relative_uri_roundtrip (line 28) | async def test_relative_uri_roundtrip():
function test_custom_scheme_uri_roundtrip (line 70) | async def test_custom_scheme_uri_roundtrip():
function test_uri_json_roundtrip_preserves_value (line 106) | def test_uri_json_roundtrip_preserves_value():
function test_resource_contents_uri_json_roundtrip (line 128) | def test_resource_contents_uri_json_roundtrip():
FILE: tests/issues/test_1754_mime_type_parameters.py
function test_mime_type_with_parameters (line 15) | async def test_mime_type_with_parameters():
function test_mime_type_with_parameters_and_space (line 29) | async def test_mime_type_with_parameters_and_space():
function test_mime_type_with_multiple_parameters (line 42) | async def test_mime_type_with_multiple_parameters():
function test_mime_type_preserved_in_read_resource (line 55) | async def test_mime_type_preserved_in_read_resource():
FILE: tests/issues/test_176_progress_token.py
function test_progress_token_zero_first_call (line 12) | async def test_progress_token_zero_first_call():
FILE: tests/issues/test_188_concurrency.py
function test_messages_are_executed_concurrently_tools (line 9) | async def test_messages_are_executed_concurrently_tools():
function test_messages_are_executed_concurrently_tools_and_resources (line 50) | async def test_messages_are_executed_concurrently_tools_and_resources():
FILE: tests/issues/test_192_request_id.py
function test_request_id_match (line 21) | async def test_request_id_match() -> None:
FILE: tests/issues/test_342_base64_encoding.py
function test_server_base64_encoding (line 18) | async def test_server_base64_encoding():
FILE: tests/issues/test_355_type_error.py
class Database (line 8) | class Database: # Replace with your actual DB type
method connect (line 10) | async def connect(cls): # pragma: no cover
method disconnect (line 13) | async def disconnect(self): # pragma: no cover
method query (line 16) | def query(self): # pragma: no cover
class AppContext (line 25) | class AppContext:
function app_lifespan (line 30) | async def app_lifespan(server: MCPServer) -> AsyncIterator[AppContext]: ...
function query_db (line 47) | def query_db(ctx: Context[AppContext]) -> str: # pragma: no cover
FILE: tests/issues/test_552_windows_hang.py
function test_windows_stdio_client_with_session (line 15) | async def test_windows_stdio_client_with_session():
FILE: tests/issues/test_88_random_error.py
function test_notification_validation_error (line 19) | async def test_notification_validation_error(tmp_path: Path):
FILE: tests/issues/test_973_url_decoding.py
function test_template_matches_decodes_space (line 9) | def test_template_matches_decodes_space():
function test_template_matches_decodes_accented_characters (line 26) | def test_template_matches_decodes_accented_characters():
function test_template_matches_decodes_complex_phrase (line 43) | def test_template_matches_decodes_complex_phrase():
function test_template_matches_preserves_plus_sign (line 60) | def test_template_matches_preserves_plus_sign():
FILE: tests/issues/test_malformed_input.py
function test_malformed_initialize_request_does_not_crash_server (line 14) | async def test_malformed_initialize_request_does_not_crash_server():
function test_multiple_concurrent_malformed_requests (line 94) | async def test_multiple_concurrent_malformed_requests():
FILE: tests/server/auth/middleware/test_auth_context.py
class MockApp (line 17) | class MockApp:
method __init__ (line 20) | def __init__(self):
method __call__ (line 27) | async def __call__(self, scope: Scope, receive: Receive, send: Send) -...
function valid_access_token (
Condensed preview — 432 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,755K chars).
[
{
"path": ".claude/commands/review-pr.md",
"chars": 3756,
"preview": "Review the pull request: $ARGUMENTS\n\nFollow these steps carefully. Use the `gh` CLI for all GitHub interactions.\n\n## Ste"
},
{
"path": ".git-blame-ignore-revs",
"chars": 307,
"preview": "# Applied 120 line-length rule to all files: https://github.com/modelcontextprotocol/python-sdk/pull/856\n543961968c0634e"
},
{
"path": ".gitattribute",
"chars": 45,
"preview": "# Generated\nuv.lock linguist-generated=true\n"
},
{
"path": ".github/ISSUE_TEMPLATE/bug.yaml",
"chars": 1652,
"preview": "name: 🐛 MCP Python SDK Bug\ndescription: Report a bug or unexpected behavior in the MCP Python SDK\nlabels: [\"need confirm"
},
{
"path": ".github/ISSUE_TEMPLATE/config.yaml",
"chars": 28,
"preview": "blank_issues_enabled: false\n"
},
{
"path": ".github/ISSUE_TEMPLATE/feature-request.yaml",
"chars": 876,
"preview": "name: 🚀 MCP Python SDK Feature Request\ndescription: \"Suggest a new feature for the MCP Python SDK\"\nlabels: [\"feature req"
},
{
"path": ".github/ISSUE_TEMPLATE/question.yaml",
"chars": 1026,
"preview": "name: ❓ MCP Python SDK Question\ndescription: \"Ask a question about the MCP Python SDK\"\nlabels: [\"question\"]\n\nbody:\n - t"
},
{
"path": ".github/actions/conformance/client.py",
"chars": 14661,
"preview": "\"\"\"MCP unified conformance test client.\n\nThis client is designed to work with the @modelcontextprotocol/conformance npm "
},
{
"path": ".github/actions/conformance/run-server.sh",
"chars": 797,
"preview": "#!/bin/bash\nset -e\n\nPORT=\"${PORT:-3001}\"\nSERVER_URL=\"http://localhost:${PORT}/mcp\"\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_"
},
{
"path": ".github/dependabot.yml",
"chars": 185,
"preview": "version: 2\nupdates:\n - package-ecosystem: \"github-actions\"\n directory: \"/\"\n schedule:\n interval: monthly\n "
},
{
"path": ".github/workflows/claude-code-review.yml",
"chars": 1260,
"preview": "# Source: https://github.com/anthropics/claude-code-action/blob/main/docs/code-review.md\nname: Claude Code Review\n\non:\n "
},
{
"path": ".github/workflows/claude.yml",
"chars": 1442,
"preview": "# Source: https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md\nname: Claude Code\n\non:\n issue_commen"
},
{
"path": ".github/workflows/comment-on-release.yml",
"chars": 5251,
"preview": "name: Comment on PRs in Release\n\non:\n release:\n types: [published]\n\npermissions:\n pull-requests: write\n contents: "
},
{
"path": ".github/workflows/conformance.yml",
"chars": 1441,
"preview": "name: Conformance Tests\n\non:\n push:\n branches: [main]\n pull_request:\n workflow_dispatch:\n\nconcurrency:\n group: co"
},
{
"path": ".github/workflows/main.yml",
"chars": 435,
"preview": "name: CI\n\non:\n push:\n branches: [\"main\", \"v1.x\"]\n tags: [\"v*.*.*\"]\n pull_request:\n branches: [\"main\", \"v1.x\"]"
},
{
"path": ".github/workflows/publish-docs-manually.yml",
"chars": 1049,
"preview": "name: Publish Docs manually\n\non:\n workflow_dispatch:\n\njobs:\n docs-publish:\n runs-on: ubuntu-latest\n permissions:"
},
{
"path": ".github/workflows/publish-pypi.yml",
"chars": 2343,
"preview": "name: Publishing\n\non:\n release:\n types: [published]\n\njobs:\n release-build:\n name: Build distribution\n runs-on"
},
{
"path": ".github/workflows/shared.yml",
"chars": 3059,
"preview": "name: Shared Checks\n\non:\n workflow_call:\n\npermissions:\n contents: read\n\nenv:\n COLUMNS: 150\n\njobs:\n pre-commit:\n r"
},
{
"path": ".github/workflows/weekly-lockfile-update.yml",
"chars": 1161,
"preview": "name: Weekly Lockfile Update\n\non:\n workflow_dispatch:\n schedule:\n # Every Thursday at 8:00 UTC\n - cron: \"0 8 * *"
},
{
"path": ".gitignore",
"chars": 3246,
"preview": ".DS_Store\nscratch/\n\n# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Di"
},
{
"path": ".pre-commit-config.yaml",
"chars": 1944,
"preview": "fail_fast: true\n\nrepos:\n - repo: https://github.com/pre-commit/pre-commit-hooks\n rev: v6.0.0\n hooks:\n - id: "
},
{
"path": "CLAUDE.md",
"chars": 6404,
"preview": "# Development Guidelines\n\nThis document contains critical information about working with this codebase. Follow these gui"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 5231,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participa"
},
{
"path": "CONTRIBUTING.md",
"chars": 5216,
"preview": "# Contributing\n\nThank you for your interest in contributing to the MCP Python SDK! This document provides guidelines and"
},
{
"path": "LICENSE",
"chars": 1071,
"preview": "MIT License\n\nCopyright (c) 2024 Anthropic, PBC\n\nPermission is hereby granted, free of charge, to any person obtaining a "
},
{
"path": "README.md",
"chars": 88162,
"preview": "# MCP Python SDK\n\n<div align=\"center\">\n\n<strong>Python implementation of the Model Context Protocol (MCP)</strong>\n\n[ so installation is as simp"
},
{
"path": "docs/low-level-server.md",
"chars": 140,
"preview": "# Low-Level Server\n\n!!! warning \"Under Construction\"\n\n This page is currently being written. Check back soon for comp"
},
{
"path": "docs/migration.md",
"chars": 30667,
"preview": "# Migration Guide: v1 to v2\n\nThis guide covers the breaking changes introduced in v2 of the MCP Python SDK and how to up"
},
{
"path": "docs/testing.md",
"chars": 2224,
"preview": "# Testing MCP Servers\n\nThe Python SDK provides a `Client` class for testing MCP servers with an in-memory transport.\nThi"
},
{
"path": "examples/README.md",
"chars": 207,
"preview": "# Python SDK Examples\n\nThis folders aims to provide simple examples of using the Python SDK. Please refer to the\n[server"
},
{
"path": "examples/clients/simple-auth-client/README.md",
"chars": 2742,
"preview": "# Simple Auth Client Example\n\nA demonstration of how to use the MCP Python SDK with OAuth authentication over streamable"
},
{
"path": "examples/clients/simple-auth-client/mcp_simple_auth_client/__init__.py",
"chars": 54,
"preview": "\"\"\"Simple OAuth client for MCP simple-auth server.\"\"\"\n"
},
{
"path": "examples/clients/simple-auth-client/mcp_simple_auth_client/main.py",
"chars": 13946,
"preview": "#!/usr/bin/env python3\n\"\"\"Simple MCP client example with OAuth authentication support.\n\nThis client connects to an MCP s"
},
{
"path": "examples/clients/simple-auth-client/pyproject.toml",
"chars": 1096,
"preview": "[project]\nname = \"mcp-simple-auth-client\"\nversion = \"0.1.0\"\ndescription = \"A simple OAuth client for the MCP simple-auth"
},
{
"path": "examples/clients/simple-chatbot/README.MD",
"chars": 3485,
"preview": "# MCP Simple Chatbot\n\nThis example demonstrates how to integrate the Model Context Protocol (MCP) into a simple CLI chat"
},
{
"path": "examples/clients/simple-chatbot/mcp_simple_chatbot/main.py",
"chars": 14962,
"preview": "from __future__ import annotations\n\nimport asyncio\nimport json\nimport logging\nimport os\nimport shutil\nfrom contextlib im"
},
{
"path": "examples/clients/simple-chatbot/mcp_simple_chatbot/requirements.txt",
"chars": 65,
"preview": "python-dotenv>=1.0.0\nrequests>=2.31.0\nmcp>=1.0.0\nuvicorn>=0.32.1\n"
},
{
"path": "examples/clients/simple-chatbot/mcp_simple_chatbot/servers_config.json",
"chars": 247,
"preview": "{\n \"mcpServers\": {\n \"sqlite\": {\n \"command\": \"uvx\",\n \"args\": [\"mcp-server-sqlite\", \"--db-path\", \"./test.db\""
},
{
"path": "examples/clients/simple-chatbot/pyproject.toml",
"chars": 1124,
"preview": "[project]\nname = \"mcp-simple-chatbot\"\nversion = \"0.1.0\"\ndescription = \"A simple CLI chatbot using the Model Context Prot"
},
{
"path": "examples/clients/simple-task-client/README.md",
"chars": 871,
"preview": "# Simple Task Client\n\nA minimal MCP client demonstrating polling for task results over streamable HTTP.\n\n## Running\n\nFir"
},
{
"path": "examples/clients/simple-task-client/mcp_simple_task_client/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "examples/clients/simple-task-client/mcp_simple_task_client/__main__.py",
"chars": 79,
"preview": "import sys\n\nfrom .main import main\n\nsys.exit(main()) # type: ignore[call-arg]\n"
},
{
"path": "examples/clients/simple-task-client/mcp_simple_task_client/main.py",
"chars": 1844,
"preview": "\"\"\"Simple task client demonstrating MCP tasks polling over streamable HTTP.\"\"\"\n\nimport asyncio\n\nimport click\nfrom mcp im"
},
{
"path": "examples/clients/simple-task-client/pyproject.toml",
"chars": 1071,
"preview": "[project]\nname = \"mcp-simple-task-client\"\nversion = \"0.1.0\"\ndescription = \"A simple MCP client demonstrating task pollin"
},
{
"path": "examples/clients/simple-task-interactive-client/README.md",
"chars": 2381,
"preview": "# Simple Interactive Task Client\n\nA minimal MCP client demonstrating responses to interactive tasks (elicitation and sam"
},
{
"path": "examples/clients/simple-task-interactive-client/mcp_simple_task_interactive_client/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "examples/clients/simple-task-interactive-client/mcp_simple_task_interactive_client/__main__.py",
"chars": 79,
"preview": "import sys\n\nfrom .main import main\n\nsys.exit(main()) # type: ignore[call-arg]\n"
},
{
"path": "examples/clients/simple-task-interactive-client/mcp_simple_task_interactive_client/main.py",
"chars": 5013,
"preview": "\"\"\"Simple interactive task client demonstrating elicitation and sampling responses.\n\nThis example demonstrates the spec-"
},
{
"path": "examples/clients/simple-task-interactive-client/pyproject.toml",
"chars": 1172,
"preview": "[project]\nname = \"mcp-simple-task-interactive-client\"\nversion = \"0.1.0\"\ndescription = \"A simple MCP client demonstrating"
},
{
"path": "examples/clients/sse-polling-client/README.md",
"chars": 839,
"preview": "# MCP SSE Polling Demo Client\n\nDemonstrates client-side auto-reconnect for the SSE polling pattern (SEP-1699).\n\n## Featu"
},
{
"path": "examples/clients/sse-polling-client/mcp_sse_polling_client/__init__.py",
"chars": 84,
"preview": "\"\"\"SSE Polling Demo Client - demonstrates auto-reconnect for long-running tasks.\"\"\"\n"
},
{
"path": "examples/clients/sse-polling-client/mcp_sse_polling_client/main.py",
"chars": 3047,
"preview": "\"\"\"SSE Polling Demo Client\n\nDemonstrates the client-side auto-reconnect for SSE polling pattern.\n\nThis client connects t"
},
{
"path": "examples/clients/sse-polling-client/pyproject.toml",
"chars": 863,
"preview": "[project]\nname = \"mcp-sse-polling-client\"\nversion = \"0.1.0\"\ndescription = \"Demo client for SSE polling with auto-reconne"
},
{
"path": "examples/mcpserver/complex_inputs.py",
"chars": 692,
"preview": "\"\"\"MCPServer Complex inputs Example\n\nDemonstrates validation via pydantic with complex models.\n\"\"\"\n\nfrom typing import A"
},
{
"path": "examples/mcpserver/desktop.py",
"chars": 494,
"preview": "\"\"\"MCPServer Desktop Example\n\nA simple example that exposes the desktop directory as a resource.\n\"\"\"\n\nfrom pathlib impor"
},
{
"path": "examples/mcpserver/direct_call_tool_result_return.py",
"chars": 583,
"preview": "\"\"\"MCPServer Echo Server with direct CallToolResult return\"\"\"\n\nfrom typing import Annotated\n\nfrom pydantic import BaseMo"
},
{
"path": "examples/mcpserver/echo.py",
"chars": 493,
"preview": "\"\"\"MCPServer Echo Server\"\"\"\n\nfrom mcp.server.mcpserver import MCPServer\n\n# Create server\nmcp = MCPServer(\"Echo Server\")\n"
},
{
"path": "examples/mcpserver/icons_demo.py",
"chars": 1531,
"preview": "\"\"\"MCPServer Icons Demo Server\n\nDemonstrates using icons with tools, resources, prompts, and implementation.\n\"\"\"\n\nimport"
},
{
"path": "examples/mcpserver/logging_and_progress.py",
"chars": 1022,
"preview": "\"\"\"MCPServer Echo Server that sends log messages and progress updates to the client\"\"\"\n\nimport asyncio\n\nfrom mcp.server."
},
{
"path": "examples/mcpserver/memory.py",
"chars": 10447,
"preview": "# /// script\n# dependencies = [\"pydantic-ai-slim[openai]\", \"asyncpg\", \"numpy\", \"pgvector\"]\n# ///\n\n# uv pip install 'pyda"
},
{
"path": "examples/mcpserver/parameter_descriptions.py",
"chars": 633,
"preview": "\"\"\"MCPServer Example showing parameter descriptions\"\"\"\n\nfrom pydantic import Field\n\nfrom mcp.server.mcpserver import MCP"
},
{
"path": "examples/mcpserver/readme-quickstart.py",
"chars": 377,
"preview": "from mcp.server.mcpserver import MCPServer\n\n# Create an MCP server\nmcp = MCPServer(\"Demo\")\n\n\n# Add an addition tool\n@mcp"
},
{
"path": "examples/mcpserver/screenshot.py",
"chars": 751,
"preview": "\"\"\"MCPServer Screenshot Example\n\nGive Claude a tool to capture and view screenshots.\n\"\"\"\n\nimport io\n\nfrom mcp.server.mcp"
},
{
"path": "examples/mcpserver/simple_echo.py",
"chars": 208,
"preview": "\"\"\"MCPServer Echo Server\"\"\"\n\nfrom mcp.server.mcpserver import MCPServer\n\n# Create server\nmcp = MCPServer(\"Echo Server\")\n"
},
{
"path": "examples/mcpserver/text_me.py",
"chars": 2071,
"preview": "# /// script\n# dependencies = []\n# ///\n\n\"\"\"MCPServer Text Me Server\n--------------------------------\nThis defines a simp"
},
{
"path": "examples/mcpserver/unicode_example.py",
"chars": 1725,
"preview": "\"\"\"Example MCPServer server that uses Unicode characters in various places to help test\nUnicode handling in tools and in"
},
{
"path": "examples/mcpserver/weather_structured.py",
"chars": 7593,
"preview": "\"\"\"MCPServer Weather Example with Structured Output\n\nDemonstrates how to use structured output with tools to return\nwell"
},
{
"path": "examples/servers/everything-server/README.md",
"chars": 1149,
"preview": "# MCP Everything Server\n\nA comprehensive MCP server implementing all protocol features for conformance testing.\n\n## Over"
},
{
"path": "examples/servers/everything-server/mcp_everything_server/__init__.py",
"chars": 92,
"preview": "\"\"\"MCP Everything Server - Comprehensive conformance test server.\"\"\"\n\n__version__ = \"0.1.0\"\n"
},
{
"path": "examples/servers/everything-server/mcp_everything_server/__main__.py",
"chars": 118,
"preview": "\"\"\"CLI entry point for the MCP Everything Server.\"\"\"\n\nfrom .server import main\n\nif __name__ == \"__main__\":\n main()\n"
},
{
"path": "examples/servers/everything-server/mcp_everything_server/server.py",
"chars": 15778,
"preview": "#!/usr/bin/env python3\n\"\"\"MCP Everything Server - Conformance Test Server\n\nServer implementing all MCP features for conf"
},
{
"path": "examples/servers/everything-server/pyproject.toml",
"chars": 968,
"preview": "[project]\nname = \"mcp-everything-server\"\nversion = \"0.1.0\"\ndescription = \"Comprehensive MCP server implementing all prot"
},
{
"path": "examples/servers/simple-auth/README.md",
"chars": 4129,
"preview": "# MCP OAuth Authentication Demo\n\nThis example demonstrates OAuth 2.0 authentication with the Model Context Protocol usin"
},
{
"path": "examples/servers/simple-auth/mcp_simple_auth/__init__.py",
"chars": 58,
"preview": "\"\"\"Simple MCP server with GitHub OAuth authentication.\"\"\"\n"
},
{
"path": "examples/servers/simple-auth/mcp_simple_auth/__main__.py",
"chars": 176,
"preview": "\"\"\"Main entry point for simple MCP server with GitHub OAuth authentication.\"\"\"\n\nimport sys\n\nfrom mcp_simple_auth.server "
},
{
"path": "examples/servers/simple-auth/mcp_simple_auth/auth_server.py",
"chars": 6162,
"preview": "\"\"\"Authorization Server for MCP Split Demo.\n\nThis server handles OAuth flows, client registration, and token issuance.\nC"
},
{
"path": "examples/servers/simple-auth/mcp_simple_auth/legacy_as_server.py",
"chars": 4702,
"preview": "\"\"\"Legacy Combined Authorization Server + Resource Server for MCP.\n\nThis server implements the old spec where MCP server"
},
{
"path": "examples/servers/simple-auth/mcp_simple_auth/py.typed",
"chars": 0,
"preview": ""
},
{
"path": "examples/servers/simple-auth/mcp_simple_auth/server.py",
"chars": 5349,
"preview": "\"\"\"MCP Resource Server with Token Introspection.\n\nThis server validates tokens via Authorization Server introspection an"
},
{
"path": "examples/servers/simple-auth/mcp_simple_auth/simple_auth_provider.py",
"chars": 10600,
"preview": "\"\"\"Simple OAuth provider for MCP servers.\n\nThis module contains a basic OAuth implementation using hardcoded user creden"
},
{
"path": "examples/servers/simple-auth/mcp_simple_auth/token_verifier.py",
"chars": 4239,
"preview": "\"\"\"Example token verifier implementation using OAuth 2.0 Token Introspection (RFC 7662).\"\"\"\n\nimport logging\nfrom typing "
},
{
"path": "examples/servers/simple-auth/pyproject.toml",
"chars": 909,
"preview": "[project]\nname = \"mcp-simple-auth\"\nversion = \"0.1.0\"\ndescription = \"A simple MCP server demonstrating OAuth authenticati"
},
{
"path": "examples/servers/simple-pagination/README.md",
"chars": 2485,
"preview": "# MCP Simple Pagination\n\nA simple MCP server demonstrating pagination for tools, resources, and prompts using cursor-bas"
},
{
"path": "examples/servers/simple-pagination/mcp_simple_pagination/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "examples/servers/simple-pagination/mcp_simple_pagination/__main__.py",
"chars": 81,
"preview": "import sys\n\nfrom .server import main\n\nsys.exit(main()) # type: ignore[call-arg]\n"
},
{
"path": "examples/servers/simple-pagination/mcp_simple_pagination/server.py",
"chars": 5789,
"preview": "\"\"\"Simple MCP server demonstrating pagination for tools, resources, and prompts.\n\nThis example shows how to implement pa"
},
{
"path": "examples/servers/simple-pagination/pyproject.toml",
"chars": 1167,
"preview": "[project]\nname = \"mcp-simple-pagination\"\nversion = \"0.1.0\"\ndescription = \"A simple MCP server demonstrating pagination f"
},
{
"path": "examples/servers/simple-prompt/README.md",
"chars": 1509,
"preview": "# MCP Simple Prompt\n\nA simple MCP server that exposes a customizable prompt template with optional context and topic par"
},
{
"path": "examples/servers/simple-prompt/mcp_simple_prompt/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "examples/servers/simple-prompt/mcp_simple_prompt/__main__.py",
"chars": 81,
"preview": "import sys\n\nfrom .server import main\n\nsys.exit(main()) # type: ignore[call-arg]\n"
},
{
"path": "examples/servers/simple-prompt/mcp_simple_prompt/server.py",
"chars": 3066,
"preview": "import anyio\nimport click\nfrom mcp import types\nfrom mcp.server import Server, ServerRequestContext\n\n\ndef create_message"
},
{
"path": "examples/servers/simple-prompt/pyproject.toml",
"chars": 1111,
"preview": "[project]\nname = \"mcp-simple-prompt\"\nversion = \"0.1.0\"\ndescription = \"A simple MCP server exposing a customizable prompt"
},
{
"path": "examples/servers/simple-resource/README.md",
"chars": 1262,
"preview": "# MCP Simple Resource\n\nA simple MCP server that exposes sample text files as resources.\n\n## Usage\n\nStart the server usin"
},
{
"path": "examples/servers/simple-resource/mcp_simple_resource/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "examples/servers/simple-resource/mcp_simple_resource/__main__.py",
"chars": 81,
"preview": "import sys\n\nfrom .server import main\n\nsys.exit(main()) # type: ignore[call-arg]\n"
},
{
"path": "examples/servers/simple-resource/mcp_simple_resource/server.py",
"chars": 2609,
"preview": "from urllib.parse import urlparse\n\nimport anyio\nimport click\nfrom mcp import types\nfrom mcp.server import Server, Server"
},
{
"path": "examples/servers/simple-resource/pyproject.toml",
"chars": 1121,
"preview": "[project]\nname = \"mcp-simple-resource\"\nversion = \"0.1.0\"\ndescription = \"A simple MCP server exposing sample text resourc"
},
{
"path": "examples/servers/simple-streamablehttp/README.md",
"chars": 1813,
"preview": "# MCP Simple StreamableHttp Server Example\n\nA simple MCP server example demonstrating the StreamableHttp transport, whic"
},
{
"path": "examples/servers/simple-streamablehttp/mcp_simple_streamablehttp/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "examples/servers/simple-streamablehttp/mcp_simple_streamablehttp/__main__.py",
"chars": 90,
"preview": "from .server import main\n\nif __name__ == \"__main__\":\n main() # type: ignore[call-arg]\n"
},
{
"path": "examples/servers/simple-streamablehttp/mcp_simple_streamablehttp/event_store.py",
"chars": 3485,
"preview": "\"\"\"In-memory event store for demonstrating resumability functionality.\n\nThis is a simple implementation intended for exa"
},
{
"path": "examples/servers/simple-streamablehttp/mcp_simple_streamablehttp/server.py",
"chars": 5140,
"preview": "import logging\n\nimport anyio\nimport click\nimport uvicorn\nfrom mcp import types\nfrom mcp.server import Server, ServerRequ"
},
{
"path": "examples/servers/simple-streamablehttp/pyproject.toml",
"chars": 984,
"preview": "[project]\nname = \"mcp-simple-streamablehttp\"\nversion = \"0.1.0\"\ndescription = \"A simple MCP server exposing a StreamableH"
},
{
"path": "examples/servers/simple-streamablehttp-stateless/README.md",
"chars": 1401,
"preview": "# MCP Simple StreamableHttp Stateless Server Example\n\nA stateless MCP server example demonstrating the StreamableHttp tr"
},
{
"path": "examples/servers/simple-streamablehttp-stateless/mcp_simple_streamablehttp_stateless/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "examples/servers/simple-streamablehttp-stateless/mcp_simple_streamablehttp_stateless/__main__.py",
"chars": 154,
"preview": "from .server import main\n\nif __name__ == \"__main__\":\n # Click will handle CLI arguments\n import sys\n\n sys.exit("
},
{
"path": "examples/servers/simple-streamablehttp-stateless/mcp_simple_streamablehttp_stateless/server.py",
"chars": 3806,
"preview": "import logging\n\nimport anyio\nimport click\nimport uvicorn\nfrom mcp import types\nfrom mcp.server import Server, ServerRequ"
},
{
"path": "examples/servers/simple-streamablehttp-stateless/pyproject.toml",
"chars": 1053,
"preview": "[project]\nname = \"mcp-simple-streamablehttp-stateless\"\nversion = \"0.1.0\"\ndescription = \"A simple MCP server exposing a S"
},
{
"path": "examples/servers/simple-task/README.md",
"chars": 778,
"preview": "# Simple Task Server\n\nA minimal MCP server demonstrating the experimental tasks feature over streamable HTTP.\n\n## Runnin"
},
{
"path": "examples/servers/simple-task/mcp_simple_task/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "examples/servers/simple-task/mcp_simple_task/__main__.py",
"chars": 81,
"preview": "import sys\n\nfrom .server import main\n\nsys.exit(main()) # type: ignore[call-arg]\n"
},
{
"path": "examples/servers/simple-task/mcp_simple_task/server.py",
"chars": 2282,
"preview": "\"\"\"Simple task server demonstrating MCP tasks over streamable HTTP.\"\"\"\n\nimport anyio\nimport click\nimport uvicorn\nfrom mc"
},
{
"path": "examples/servers/simple-task/pyproject.toml",
"chars": 1059,
"preview": "[project]\nname = \"mcp-simple-task\"\nversion = \"0.1.0\"\ndescription = \"A simple MCP server demonstrating tasks\"\nreadme = \"R"
},
{
"path": "examples/servers/simple-task-interactive/README.md",
"chars": 2131,
"preview": "# Simple Interactive Task Server\n\nA minimal MCP server demonstrating interactive tasks with elicitation and sampling.\n\n#"
},
{
"path": "examples/servers/simple-task-interactive/mcp_simple_task_interactive/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "examples/servers/simple-task-interactive/mcp_simple_task_interactive/__main__.py",
"chars": 81,
"preview": "import sys\n\nfrom .server import main\n\nsys.exit(main()) # type: ignore[call-arg]\n"
},
{
"path": "examples/servers/simple-task-interactive/mcp_simple_task_interactive/server.py",
"chars": 5101,
"preview": "\"\"\"Simple interactive task server demonstrating elicitation and sampling.\n\nThis example shows the simplified task API wh"
},
{
"path": "examples/servers/simple-task-interactive/pyproject.toml",
"chars": 1183,
"preview": "[project]\nname = \"mcp-simple-task-interactive\"\nversion = \"0.1.0\"\ndescription = \"A simple MCP server demonstrating intera"
},
{
"path": "examples/servers/simple-tool/README.md",
"chars": 1206,
"preview": "\nA simple MCP server that exposes a website fetching tool.\n\n## Usage\n\nStart the server using either stdio (default) or S"
},
{
"path": "examples/servers/simple-tool/mcp_simple_tool/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "examples/servers/simple-tool/mcp_simple_tool/__main__.py",
"chars": 81,
"preview": "import sys\n\nfrom .server import main\n\nsys.exit(main()) # type: ignore[call-arg]\n"
},
{
"path": "examples/servers/simple-tool/mcp_simple_tool/server.py",
"chars": 2521,
"preview": "import anyio\nimport click\nfrom mcp import types\nfrom mcp.server import Server, ServerRequestContext\nfrom mcp.shared._htt"
},
{
"path": "examples/servers/simple-tool/pyproject.toml",
"chars": 1103,
"preview": "[project]\nname = \"mcp-simple-tool\"\nversion = \"0.1.0\"\ndescription = \"A simple MCP server exposing a website fetching tool"
},
{
"path": "examples/servers/sse-polling-demo/README.md",
"chars": 956,
"preview": "# MCP SSE Polling Demo Server\n\nDemonstrates the SSE polling pattern with server-initiated stream close for long-running "
},
{
"path": "examples/servers/sse-polling-demo/mcp_sse_polling_demo/__init__.py",
"chars": 86,
"preview": "\"\"\"SSE Polling Demo Server - demonstrates close_sse_stream for long-running tasks.\"\"\"\n"
},
{
"path": "examples/servers/sse-polling-demo/mcp_sse_polling_demo/__main__.py",
"chars": 116,
"preview": "\"\"\"Entry point for the SSE Polling Demo server.\"\"\"\n\nfrom .server import main\n\nif __name__ == \"__main__\":\n main()\n"
},
{
"path": "examples/servers/sse-polling-demo/mcp_sse_polling_demo/event_store.py",
"chars": 3682,
"preview": "\"\"\"In-memory event store for demonstrating resumability functionality.\n\nThis is a simple implementation intended for exa"
},
{
"path": "examples/servers/sse-polling-demo/mcp_sse_polling_demo/server.py",
"chars": 5334,
"preview": "\"\"\"SSE Polling Demo Server\n\nDemonstrates the SSE polling pattern with close_sse_stream() for long-running tasks.\n\nFeatur"
},
{
"path": "examples/servers/sse-polling-demo/pyproject.toml",
"chars": 949,
"preview": "[project]\nname = \"mcp-sse-polling-demo\"\nversion = \"0.1.0\"\ndescription = \"Demo server showing SSE polling with close_sse_"
},
{
"path": "examples/servers/structured-output-lowlevel/mcp_structured_output_lowlevel/__init__.py",
"chars": 62,
"preview": "\"\"\"Example of structured output with low-level MCP server.\"\"\"\n"
},
{
"path": "examples/servers/structured-output-lowlevel/mcp_structured_output_lowlevel/__main__.py",
"chars": 2977,
"preview": "#!/usr/bin/env python3\n\"\"\"Example low-level MCP server demonstrating structured output support.\n\nThis example shows how "
},
{
"path": "examples/servers/structured-output-lowlevel/pyproject.toml",
"chars": 189,
"preview": "[project]\nname = \"mcp-structured-output-lowlevel\"\nversion = \"0.1.0\"\ndescription = \"Example of structured output with low"
},
{
"path": "examples/snippets/clients/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "examples/snippets/clients/completion_client.py",
"chars": 3036,
"preview": "\"\"\"cd to the `examples/snippets` directory and run:\nuv run completion-client\n\"\"\"\n\nimport asyncio\nimport os\n\nfrom mcp imp"
},
{
"path": "examples/snippets/clients/display_utilities.py",
"chars": 2096,
"preview": "\"\"\"cd to the `examples/snippets` directory and run:\nuv run display-utilities-client\n\"\"\"\n\nimport asyncio\nimport os\n\nfrom "
},
{
"path": "examples/snippets/clients/oauth_client.py",
"chars": 2884,
"preview": "\"\"\"Before running, specify running MCP RS server URL.\nTo spin up RS server locally, see\n examples/servers/simple-auth"
},
{
"path": "examples/snippets/clients/pagination_client.py",
"chars": 1259,
"preview": "\"\"\"Example of consuming paginated MCP endpoints from a client.\"\"\"\n\nimport asyncio\n\nfrom mcp.client.session import Client"
},
{
"path": "examples/snippets/clients/parsing_tool_results.py",
"chars": 2525,
"preview": "\"\"\"examples/snippets/clients/parsing_tool_results.py\"\"\"\n\nimport asyncio\n\nfrom mcp import ClientSession, StdioServerParam"
},
{
"path": "examples/snippets/clients/stdio_client.py",
"chars": 2988,
"preview": "\"\"\"cd to the `examples/snippets/clients` directory and run:\nuv run client\n\"\"\"\n\nimport asyncio\nimport os\n\nfrom mcp import"
},
{
"path": "examples/snippets/clients/streamable_basic.py",
"chars": 775,
"preview": "\"\"\"Run from the repository root:\nuv run examples/snippets/clients/streamable_basic.py\n\"\"\"\n\nimport asyncio\n\nfrom mcp impo"
},
{
"path": "examples/snippets/clients/url_elicitation_client.py",
"chars": 10584,
"preview": "\"\"\"URL Elicitation Client Example.\n\nDemonstrates how clients handle URL elicitation requests from servers.\nThis is the P"
},
{
"path": "examples/snippets/pyproject.toml",
"chars": 645,
"preview": "[project]\nname = \"mcp-snippets\"\nversion = \"0.1.0\"\ndescription = \"MCP Example Snippets\"\nrequires-python = \">=3.10\"\ndepend"
},
{
"path": "examples/snippets/servers/__init__.py",
"chars": 1266,
"preview": "\"\"\"MCP Snippets.\n\nThis package contains simple examples of MCP server features.\nEach server demonstrates a single featur"
},
{
"path": "examples/snippets/servers/basic_prompt.py",
"chars": 526,
"preview": "from mcp.server.mcpserver import MCPServer\nfrom mcp.server.mcpserver.prompts import base\n\nmcp = MCPServer(name=\"Prompt E"
},
{
"path": "examples/snippets/servers/basic_resource.py",
"chars": 450,
"preview": "from mcp.server.mcpserver import MCPServer\n\nmcp = MCPServer(name=\"Resource Example\")\n\n\n@mcp.resource(\"file://documents/{"
},
{
"path": "examples/snippets/servers/basic_tool.py",
"chars": 391,
"preview": "from mcp.server.mcpserver import MCPServer\n\nmcp = MCPServer(name=\"Tool Example\")\n\n\n@mcp.tool()\ndef sum(a: int, b: int) -"
},
{
"path": "examples/snippets/servers/completion.py",
"chars": 1688,
"preview": "from mcp.server.mcpserver import MCPServer\nfrom mcp.types import (\n Completion,\n CompletionArgument,\n Completio"
},
{
"path": "examples/snippets/servers/direct_call_tool_result.py",
"chars": 1245,
"preview": "\"\"\"Example showing direct CallToolResult return for advanced control.\"\"\"\n\nfrom typing import Annotated\n\nfrom pydantic im"
},
{
"path": "examples/snippets/servers/direct_execution.py",
"chars": 553,
"preview": "\"\"\"Example showing direct execution of an MCP server.\n\nThis is the simplest way to run an MCP server directly.\ncd to the"
},
{
"path": "examples/snippets/servers/elicitation.py",
"chars": 3605,
"preview": "\"\"\"Elicitation examples demonstrating form and URL mode elicitation.\n\nForm mode elicitation collects structured, non-sen"
},
{
"path": "examples/snippets/servers/images.py",
"chars": 395,
"preview": "\"\"\"Example showing image handling with MCPServer.\"\"\"\n\nfrom PIL import Image as PILImage\n\nfrom mcp.server.mcpserver impor"
},
{
"path": "examples/snippets/servers/lifespan_example.py",
"chars": 1388,
"preview": "\"\"\"Example showing lifespan support for startup/shutdown with strong typing.\"\"\"\n\nfrom collections.abc import AsyncIterat"
},
{
"path": "examples/snippets/servers/lowlevel/__init__.py",
"chars": 52,
"preview": "\"\"\"Low-level server examples for MCP Python SDK.\"\"\"\n"
},
{
"path": "examples/snippets/servers/lowlevel/basic.py",
"chars": 1769,
"preview": "\"\"\"Run from the repository root:\nuv run examples/snippets/servers/lowlevel/basic.py\n\"\"\"\n\nimport asyncio\n\nimport mcp.serv"
},
{
"path": "examples/snippets/servers/lowlevel/direct_call_tool_result.py",
"chars": 1846,
"preview": "\"\"\"Run from the repository root:\nuv run examples/snippets/servers/lowlevel/direct_call_tool_result.py\n\"\"\"\n\nimport asynci"
},
{
"path": "examples/snippets/servers/lowlevel/lifespan.py",
"chars": 2781,
"preview": "\"\"\"Run from the repository root:\nuv run examples/snippets/servers/lowlevel/lifespan.py\n\"\"\"\n\nfrom collections.abc import "
},
{
"path": "examples/snippets/servers/lowlevel/structured_output.py",
"chars": 2555,
"preview": "\"\"\"Run from the repository root:\nuv run examples/snippets/servers/lowlevel/structured_output.py\n\"\"\"\n\nimport asyncio\nimpo"
},
{
"path": "examples/snippets/servers/mcpserver_quickstart.py",
"chars": 1052,
"preview": "\"\"\"MCPServer quickstart example.\n\nRun from the repository root:\n uv run examples/snippets/servers/mcpserver_quickstar"
},
{
"path": "examples/snippets/servers/notifications.py",
"chars": 560,
"preview": "from mcp.server.mcpserver import Context, MCPServer\n\nmcp = MCPServer(name=\"Notifications Example\")\n\n\n@mcp.tool()\nasync d"
},
{
"path": "examples/snippets/servers/oauth_server.py",
"chars": 1328,
"preview": "\"\"\"Run from the repository root:\nuv run examples/snippets/servers/oauth_server.py\n\"\"\"\n\nfrom pydantic import AnyHttpUrl\n\n"
},
{
"path": "examples/snippets/servers/pagination_example.py",
"chars": 1101,
"preview": "\"\"\"Example of implementing pagination with the low-level MCP server.\"\"\"\n\nfrom mcp import types\nfrom mcp.server import Se"
},
{
"path": "examples/snippets/servers/sampling.py",
"chars": 736,
"preview": "from mcp.server.mcpserver import Context, MCPServer\nfrom mcp.types import SamplingMessage, TextContent\n\nmcp = MCPServer("
},
{
"path": "examples/snippets/servers/streamable_config.py",
"chars": 868,
"preview": "\"\"\"Run from the repository root:\nuv run examples/snippets/servers/streamable_config.py\n\"\"\"\n\nfrom mcp.server.mcpserver im"
},
{
"path": "examples/snippets/servers/streamable_http_basic_mounting.py",
"chars": 925,
"preview": "\"\"\"Basic example showing how to mount StreamableHTTP server in Starlette.\n\nRun from the repository root:\n uvicorn exa"
},
{
"path": "examples/snippets/servers/streamable_http_host_mounting.py",
"chars": 953,
"preview": "\"\"\"Example showing how to mount StreamableHTTP server using Host-based routing.\n\nRun from the repository root:\n uvico"
},
{
"path": "examples/snippets/servers/streamable_http_multiple_servers.py",
"chars": 1474,
"preview": "\"\"\"Example showing how to mount multiple StreamableHTTP servers with path configuration.\n\nRun from the repository root:\n"
},
{
"path": "examples/snippets/servers/streamable_http_path_config.py",
"chars": 860,
"preview": "\"\"\"Example showing path configuration when mounting MCPServer.\n\nRun from the repository root:\n uvicorn examples.snipp"
},
{
"path": "examples/snippets/servers/streamable_starlette_mount.py",
"chars": 1612,
"preview": "\"\"\"Run from the repository root:\nuvicorn examples.snippets.servers.streamable_starlette_mount:app --reload\n\"\"\"\n\nimport c"
},
{
"path": "examples/snippets/servers/structured_output.py",
"chars": 2534,
"preview": "\"\"\"Example showing structured output with tools.\"\"\"\n\nfrom typing import TypedDict\n\nfrom pydantic import BaseModel, Field"
},
{
"path": "examples/snippets/servers/tool_progress.py",
"chars": 585,
"preview": "from mcp.server.mcpserver import Context, MCPServer\n\nmcp = MCPServer(name=\"Progress Example\")\n\n\n@mcp.tool()\nasync def lo"
},
{
"path": "mkdocs.yml",
"chars": 3709,
"preview": "site_name: MCP Server\nsite_description: MCP Server\nstrict: true\n\nrepo_name: modelcontextprotocol/python-sdk\nrepo_url: ht"
},
{
"path": "pyproject.toml",
"chars": 7156,
"preview": "[project]\nname = \"mcp\"\ndynamic = [\"version\"]\ndescription = \"Model Context Protocol SDK\"\nreadme = \"README.md\"\nrequires-py"
},
{
"path": "scripts/test",
"chars": 360,
"preview": "#!/bin/sh\n\nset -ex\n\nuv run --frozen coverage erase\nuv run --frozen coverage run -m pytest -n auto $@\nuv run --frozen cov"
},
{
"path": "scripts/update_readme_snippets.py",
"chars": 5185,
"preview": "#!/usr/bin/env python3\n\"\"\"Update README.md with live code snippets from example files.\n\nThis script finds specially mark"
},
{
"path": "src/mcp/__init__.py",
"chars": 3263,
"preview": "from .client.client import Client\nfrom .client.session import ClientSession\nfrom .client.session_group import ClientSess"
},
{
"path": "src/mcp/cli/__init__.py",
"chars": 103,
"preview": "\"\"\"MCP CLI package.\"\"\"\n\nfrom .cli import app\n\nif __name__ == \"__main__\": # pragma: no cover\n app()\n"
},
{
"path": "src/mcp/cli/claude.py",
"chars": 5211,
"preview": "\"\"\"Claude app integration utilities.\"\"\"\n\nimport json\nimport os\nimport shutil\nimport sys\nfrom pathlib import Path\nfrom ty"
},
{
"path": "src/mcp/cli/cli.py",
"chars": 15131,
"preview": "\"\"\"MCP CLI tools.\"\"\"\n\nimport importlib.metadata\nimport importlib.util\nimport os\nimport subprocess\nimport sys\nfrom pathli"
},
{
"path": "src/mcp/client/__init__.py",
"chars": 280,
"preview": "\"\"\"MCP Client module.\"\"\"\n\nfrom mcp.client._transport import Transport\nfrom mcp.client.client import Client\nfrom mcp.clie"
},
{
"path": "src/mcp/client/__main__.py",
"chars": 2579,
"preview": "import argparse\nimport logging\nimport sys\nimport warnings\nfrom functools import partial\nfrom urllib.parse import urlpars"
},
{
"path": "src/mcp/client/_memory.py",
"chars": 3098,
"preview": "\"\"\"In-memory transport for testing MCP servers without network overhead.\"\"\"\n\nfrom __future__ import annotations\n\nfrom co"
},
{
"path": "src/mcp/client/_transport.py",
"chars": 666,
"preview": "\"\"\"Transport protocol for MCP clients.\"\"\"\n\nfrom __future__ import annotations\n\nfrom contextlib import AbstractAsyncConte"
},
{
"path": "src/mcp/client/auth/__init__.py",
"chars": 487,
"preview": "\"\"\"OAuth2 Authentication implementation for HTTPX.\n\nImplements authorization code flow with PKCE and automatic token ref"
},
{
"path": "src/mcp/client/auth/exceptions.py",
"chars": 264,
"preview": "class OAuthFlowError(Exception):\n \"\"\"Base exception for OAuth flow errors.\"\"\"\n\n\nclass OAuthTokenError(OAuthFlowError)"
},
{
"path": "src/mcp/client/auth/extensions/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "src/mcp/client/auth/extensions/client_credentials.py",
"chars": 20886,
"preview": "\"\"\"OAuth client credential extensions for MCP.\n\nProvides OAuth providers for machine-to-machine authentication flows:\n- "
},
{
"path": "src/mcp/client/auth/oauth2.py",
"chars": 29160,
"preview": "\"\"\"OAuth2 Authentication implementation for HTTPX.\n\nImplements authorization code flow with PKCE and automatic token ref"
},
{
"path": "src/mcp/client/auth/utils.py",
"chars": 11950,
"preview": "import re\nfrom urllib.parse import urljoin, urlparse\n\nfrom httpx import Request, Response\nfrom pydantic import AnyUrl, V"
}
]
// ... and 232 more files (download for full content)
About this extraction
This page contains the full source code of the modelcontextprotocol/python-sdk GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 432 files (2.5 MB), approximately 673.2k tokens, and a symbol index with 2760 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.