File size: 176,851 Bytes
f468451
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
{
  "docs": [
    {
      "id": "md_architecture_b82bfe7e",
      "url": "file://C:\\crawl\\architecture.md",
      "title": "Architecture overview",
      "content": "Architecture overview\nThis overview of the Model Context Protocol (MCP) discusses its scope and core concepts, and provides an example demonstrating each core concept.\nBecause MCP SDKs abstract away many concerns, most developers will likely find the data layer protocol section to be the most useful. It discusses how MCP servers can provide context to an AI application.\nFor specific implementation details, please refer to the documentation for your language-specific SDK.\nScope\nThe Model Context Protocol includes the following projects:\n\nMCP Specification: A specification of MCP that outlines the implementation requirements for clients and servers.\nMCP SDKs: SDKs for different programming languages that implement MCP.\nMCP Development Tools: Tools for developing MCP servers and clients, including the MCP Inspector\nMCP Reference Server Implementations: Reference implementations of MCP servers.\n\n MCP focuses solely on the protocol for context exchange—it does not dictate\n how AI applications use LLMs or manage the provided context.\n\nConcepts of MCP\nParticipants\nMCP follows a client-server architecture where an MCP host — an AI application like Claude Code or Claude Desktop — establishes connections to one or more MCP servers. The MCP host accomplishes this by creating one MCP client for each MCP server. Each MCP client maintains a dedicated one-to-one connection with its corresponding MCP server.\nThe key participants in the MCP architecture are:\n\nMCP Host: The AI application that coordinates and manages one or multiple MCP clients\nMCP Client: A component that maintains a connection to an MCP server and obtains context from an MCP server for the MCP host to use\nMCP Server: A program that provides context to MCP clients\n\nFor example: Visual Studio Code acts as an MCP host. When Visual Studio Code establishes a connection to an MCP server, such as the Sentry MCP server, the Visual Studio Code runtime instantiates an MCP client object that maintains the connection to the Sentry MCP server.\nWhen Visual Studio Code subsequently connects to another MCP server, such as the local filesystem server, the Visual Studio Code runtime instantiates an additional MCP client object to maintain this connection, hence maintaining a one-to-one\nrelationship of MCP clients to MCP servers.\n```mermaid theme={null}\ngraph TB\n subgraph \"MCP Host (AI Application)\"\n Client1[\"MCP Client 1\"]\n Client2[\"MCP Client 2\"]\n Client3[\"MCP Client 3\"]\n end\nServer1[\"MCP Server 1<br/>(e.g., Sentry)\"]\nServer2[\"MCP Server 2<br/>(e.g., Filesystem)\"]\nServer3[\"MCP Server 3<br/>(e.g., Database)\"]\n\nClient1 ---|\"One-to-one<br/>connection\"| Server1\nClient2 ---|\"One-to-one<br/>connection\"| Server2\nClient3 ---|\"One-to-one<br/>connection\"| Server3\n\n```\nNote that MCP server refers to the program that serves context data, regardless of\nwhere it runs. MCP servers can execute locally or remotely. For example, when\nClaude Desktop launches the filesystem\nserver,\nthe server runs locally on the same machine because it uses the STDIO\ntransport. This is commonly referred to as a \"local\" MCP server. The official\nSentry MCP server runs on the\nSentry platform, and uses the Streamable HTTP transport. This is commonly\nreferred to as a \"remote\" MCP server.\nLayers\nMCP consists of two layers:\n\nData layer: Defines the JSON-RPC based protocol for client-server communication, including lifecycle management, and core primitives, such as tools, resources, prompts and notifications.\nTransport layer: Defines the communication mechanisms and channels that enable data exchange between clients and servers, including transport-specific connection establishment, message framing, and authorization.\n\nConceptually the data layer is the inner layer, while the transport layer is the outer layer.\nData layer\nThe data layer implements a JSON-RPC 2.0 based exchange protocol that defines the message structure and semantics.\nThis layer includes:\n\nLifecycle management: Handles connection initialization, capability negotiation, and connection termination between clients and servers\nServer features: Enables servers to provide core functionality including tools for AI actions, resources for context data, and prompts for interaction templates from and to the client\nClient features: Enables servers to ask the client to sample from the host LLM, elicit input from the user, and log messages to the client\nUtility features: Supports additional capabilities like notifications for real-time updates and progress tracking for long-running operations\n\nTransport layer\nThe transport layer manages communication channels and authentication between clients and servers. It handles connection establishment, message framing, and secure communication between MCP participants.\nMCP supports two transport mechanisms:\n\nStdio transport: Uses standard input/output streams for direct process communication between local processes on the same machine, providing optimal performance with no network overhead.\nStreamable HTTP transport: Uses HTTP POST for client-to-server messages with optional Server-Sent Events for streaming capabilities. This transport enables remote server communication and supports standard HTTP authentication methods including bearer tokens, API keys, and custom headers. MCP recommends using OAuth to obtain authentication tokens.\n\nThe transport layer abstracts communication details from the protocol layer, enabling the same JSON-RPC 2.0 message format across all transport mechanisms.\nData Layer Protocol\nA core part of MCP is defining the schema and semantics between MCP clients and MCP servers. Developers will likely find the data layer — in particular, the set of primitives — to be the most interesting part of MCP. It is the part of MCP that defines the ways developers can share context from MCP servers to MCP clients.\nMCP uses JSON-RPC 2.0 as its underlying RPC protocol. Client and servers send requests to each other and respond accordingly. Notifications can be used when no response is required.\nLifecycle management\nMCP is a stateful protocol that requires lifecycle management. The purpose of lifecycle management is to negotiate the capabilities that both client and server support. Detailed information can be found in the specification, and the example showcases the initialization sequence.\nPrimitives\nMCP primitives are the most important concept within MCP. They define what clients and servers can offer each other. These primitives specify the types of contextual information that can be shared with AI applications and the range of actions that can be performed.\nMCP defines three core primitives that servers can expose:\n\nTools: Executable functions that AI applications can invoke to perform actions (e.g., file operations, API calls, database queries)\nResources: Data sources that provide contextual information to AI applications (e.g., file contents, database records, API responses)\nPrompts: Reusable templates that help structure interactions with language models (e.g., system prompts, few-shot examples)\n\nEach primitive type has associated methods for discovery (*/list), retrieval (*/get), and in some cases, execution (tools/call).\nMCP clients will use the */list methods to discover available primitives. For example, a client can first list all available tools (tools/list) and then execute them. This design allows listings to be dynamic.\nAs a concrete example, consider an MCP server that provides context about a database. It can expose tools for querying the database, a resource that contains the schema of the database, and a prompt that includes few-shot examples for interacting with the tools.\nFor more details about server primitives see server concepts.\nMCP also defines primitives that clients can expose. These primitives allow MCP server authors to build richer interactions.\n\nSampling: Allows servers to request language model completions from the client's AI application. This is useful when servers' authors want access to a language model, but want to stay model independent and not include a language model SDK in their MCP server. They can use the sampling/complete method to request a language model completion from the client's AI application.\nElicitation: Allows servers to request additional information from users. This is useful when servers' authors want to get more information from the user, or ask for confirmation of an action. They can use the elicitation/request method to request additional information from the user.\nLogging: Enables servers to send log messages to clients for debugging and monitoring purposes.\n\nFor more details about client primitives see client concepts.\nNotifications\nThe protocol supports real-time notifications to enable dynamic updates between servers and clients. For example, when a server's available tools change—such as when new functionality becomes available or existing tools are modified—the server can send tool update notifications to inform connected clients about these changes. Notifications are sent as JSON-RPC 2.0 notification messages (without expecting a response) and enable MCP servers to provide real-time updates to connected clients.\nExample\nData Layer\nThis section provides a step-by-step walkthrough of an MCP client-server interaction, focusing on the data layer protocol. We'll demonstrate the lifecycle sequence, tool operations, and notifications using JSON-RPC 2.0 messages.\n\n MCP begins with lifecycle management through a capability negotiation handshake. As described in the lifecycle management section, the client sends an initialize request to establish the connection and negotiate supported features.\n<CodeGroup>\n ```json Initialize Request theme={null}\n {\n \"jsonrpc\": \"2.0\",\n \"id\": 1,\n \"method\": \"initialize\",\n \"params\": {\n \"protocolVersion\": \"2025-06-18\",\n \"capabilities\": {\n \"elicitation\": {}\n },\n \"clientInfo\": {\n \"name\": \"example-client\",\n \"version\": \"1.0.0\"\n }\n }\n }\n ```\n\n ```json Initialize Response theme={null}\n {\n \"jsonrpc\": \"2.0\",\n \"id\": 1,\n \"result\": {\n \"protocolVersion\": \"2025-06-18\",\n \"capabilities\": {\n \"tools\": {\n \"listChanged\": true\n },\n \"resources\": {}\n },\n \"serverInfo\": {\n \"name\": \"example-server\",\n \"version\": \"1.0.0\"\n }\n }\n }\n ```\n</CodeGroup>\n\n#### Understanding the Initialization Exchange\n\nThe initialization process is a key part of MCP's lifecycle management and serves several critical purposes:\n\n1. **Protocol Version Negotiation**: The `protocolVersion` field (e.g., \"2025-06-18\") ensures both client and server are using compatible protocol versions. This prevents communication errors that could occur when different versions attempt to interact. If a mutually compatible version is not negotiated, the connection should be terminated.\n\n2. **Capability Discovery**: The `capabilities` object allows each party to declare what features they support, including which [primitives](#primitives) they can handle (tools, resources, prompts) and whether they support features like [notifications](#notifications). This enables efficient communication by avoiding unsupported operations.\n\n3. **Identity Exchange**: The `clientInfo` and `serverInfo` objects provide identification and versioning information for debugging and compatibility purposes.\n\nIn this example, the capability negotiation demonstrates how MCP primitives are declared:\n\n**Client Capabilities**:\n\n* `\"elicitation\": {}` - The client declares it can work with user interaction requests (can receive `elicitation/create` method calls)\n\n**Server Capabilities**:\n\n* `\"tools\": {\"listChanged\": true}` - The server supports the tools primitive AND can send `tools/list_changed` notifications when its tool list changes\n* `\"resources\": {}` - The server also supports the resources primitive (can handle `resources/list` and `resources/read` methods)\n\nAfter successful initialization, the client sends a notification to indicate it's ready:\n\n```json Notification theme={null}\n{\n \"jsonrpc\": \"2.0\",\n \"method\": \"notifications/initialized\"\n}\n```\n\n#### How This Works in AI Applications\n\nDuring initialization, the AI application's MCP client manager establishes connections to configured servers and stores their capabilities for later use. The application uses this information to determine which servers can provide specific types of functionality (tools, resources, prompts) and whether they support real-time updates.\n\n```python Pseudo-code for AI application initialization theme={null}\n# Pseudo Code\nasync with stdio_client(server_config) as (read, write):\n async with ClientSession(read, write) as session:\n init_response = await session.initialize()\n if init_response.capabilities.tools:\n app.register_mcp_server(session, supports_tools=True)\n app.set_server_ready(session)\n```\n\n Now that the connection is established, the client can discover available tools by sending a tools/list request. This request is fundamental to MCP's tool discovery mechanism — it allows clients to understand what tools are available on the server before attempting to use them.\n<CodeGroup>\n ```json Tools List Request theme={null}\n {\n \"jsonrpc\": \"2.0\",\n \"id\": 2,\n \"method\": \"tools/list\"\n }\n ```\n\n ```json Tools List Response theme={null}\n {\n \"jsonrpc\": \"2.0\",\n \"id\": 2,\n \"result\": {\n \"tools\": [\n {\n \"name\": \"calculator_arithmetic\",\n \"title\": \"Calculator\",\n \"description\": \"Perform mathematical calculations including basic arithmetic, trigonometric functions, and algebraic operations\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"properties\": {\n \"expression\": {\n \"type\": \"string\",\n \"description\": \"Mathematical expression to evaluate (e.g., '2 + 3 * 4', 'sin(30)', 'sqrt(16)')\"\n }\n },\n \"required\": [\"expression\"]\n }\n },\n {\n \"name\": \"weather_current\",\n \"title\": \"Weather Information\",\n \"description\": \"Get current weather information for any location worldwide\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"properties\": {\n \"location\": {\n \"type\": \"string\",\n \"description\": \"City name, address, or coordinates (latitude,longitude)\"\n },\n \"units\": {\n \"type\": \"string\",\n \"enum\": [\"metric\", \"imperial\", \"kelvin\"],\n \"description\": \"Temperature units to use in response\",\n \"default\": \"metric\"\n }\n },\n \"required\": [\"location\"]\n }\n }\n ]\n }\n }\n ```\n</CodeGroup>\n\n#### Understanding the Tool Discovery Request\n\nThe `tools/list` request is simple, containing no parameters.\n\n#### Understanding the Tool Discovery Response\n\nThe response contains a `tools` array that provides comprehensive metadata about each available tool. This array-based structure allows servers to expose multiple tools simultaneously while maintaining clear boundaries between different functionalities.\n\nEach tool object in the response includes several key fields:\n\n* **`name`**: A unique identifier for the tool within the server's namespace. This serves as the primary key for tool execution and should follow a clear naming pattern (e.g., `calculator_arithmetic` rather than just `calculate`)\n* **`title`**: A human-readable display name for the tool that clients can show to users\n* **`description`**: Detailed explanation of what the tool does and when to use it\n* **`inputSchema`**: A JSON Schema that defines the expected input parameters, enabling type validation and providing clear documentation about required and optional parameters\n\n#### How This Works in AI Applications\n\nThe AI application fetches available tools from all connected MCP servers and combines them into a unified tool registry that the language model can access. This allows the LLM to understand what actions it can perform and automatically generates the appropriate tool calls during conversations.\n\n```python Pseudo-code for AI application tool discovery theme={null}\n# Pseudo-code using MCP Python SDK patterns\navailable_tools = []\nfor session in app.mcp_server_sessions():\n tools_response = await session.list_tools()\n available_tools.extend(tools_response.tools)\nconversation.register_available_tools(available_tools)\n```\n\n The client can now execute a tool using the tools/call method. This demonstrates how MCP primitives are used in practice: after discovering available tools, the client can invoke them with appropriate arguments.\n#### Understanding the Tool Execution Request\n\nThe `tools/call` request follows a structured format that ensures type safety and clear communication between client and server. Note that we're using the proper tool name from the discovery response (`weather_current`) rather than a simplified name:\n\n<CodeGroup>\n ```json Tool Call Request theme={null}\n {\n \"jsonrpc\": \"2.0\",\n \"id\": 3,\n \"method\": \"tools/call\",\n \"params\": {\n \"name\": \"weather_current\",\n \"arguments\": {\n \"location\": \"San Francisco\",\n \"units\": \"imperial\"\n }\n }\n }\n ```\n\n ```json Tool Call Response theme={null}\n {\n \"jsonrpc\": \"2.0\",\n \"id\": 3,\n \"result\": {\n \"content\": [\n {\n \"type\": \"text\",\n \"text\": \"Current weather in San Francisco: 68°F, partly cloudy with light winds from the west at 8 mph. Humidity: 65%\"\n }\n ]\n }\n }\n ```\n</CodeGroup>\n\n#### Key Elements of Tool Execution\n\nThe request structure includes several important components:\n\n1. **`name`**: Must match exactly the tool name from the discovery response (`weather_current`). This ensures the server can correctly identify which tool to execute.\n\n2. **`arguments`**: Contains the input parameters as defined by the tool's `inputSchema`. In this example:\n * `location`: \"San Francisco\" (required parameter)\n * `units`: \"imperial\" (optional parameter, defaults to \"metric\" if not specified)\n\n3. **JSON-RPC Structure**: Uses standard JSON-RPC 2.0 format with unique `id` for request-response correlation.\n\n#### Understanding the Tool Execution Response\n\nThe response demonstrates MCP's flexible content system:\n\n1. **`content` Array**: Tool responses return an array of content objects, allowing for rich, multi-format responses (text, images, resources, etc.)\n\n2. **Content Types**: Each content object has a `type` field. In this example, `\"type\": \"text\"` indicates plain text content, but MCP supports various content types for different use cases.\n\n3. **Structured Output**: The response provides actionable information that the AI application can use as context for language model interactions.\n\nThis execution pattern allows AI applications to dynamically invoke server functionality and receive structured responses that can be integrated into conversations with language models.\n\n#### How This Works in AI Applications\n\nWhen the language model decides to use a tool during a conversation, the AI application intercepts the tool call, routes it to the appropriate MCP server, executes it, and returns the results back to the LLM as part of the conversation flow. This enables the LLM to access real-time data and perform actions in the external world.\n\n```python theme={null}\n# Pseudo-code for AI application tool execution\nasync def handle_tool_call(conversation, tool_name, arguments):\n session = app.find_mcp_session_for_tool(tool_name)\n result = await session.call_tool(tool_name, arguments)\n conversation.add_tool_result(result.content)\n```\n\n MCP supports real-time notifications that enable servers to inform clients about changes without being explicitly requested. This demonstrates the notification system, a key feature that keeps MCP connections synchronized and responsive.\n#### Understanding Tool List Change Notifications\n\nWhen the server's available tools change—such as when new functionality becomes available, existing tools are modified, or tools become temporarily unavailable—the server can proactively notify connected clients:\n\n```json Request theme={null}\n{\n \"jsonrpc\": \"2.0\",\n \"method\": \"notifications/tools/list_changed\"\n}\n```\n\n#### Key Features of MCP Notifications\n\n1. **No Response Required**: Notice there's no `id` field in the notification. This follows JSON-RPC 2.0 notification semantics where no response is expected or sent.\n\n2. **Capability-Based**: This notification is only sent by servers that declared `\"listChanged\": true` in their tools capability during initialization (as shown in Step 1).\n\n3. **Event-Driven**: The server decides when to send notifications based on internal state changes, making MCP connections dynamic and responsive.\n\n#### Client Response to Notifications\n\nUpon receiving this notification, the client typically reacts by requesting the updated tool list. This creates a refresh cycle that keeps the client's understanding of available tools current:\n\n```json Request theme={null}\n{\n \"jsonrpc\": \"2.0\",\n \"id\": 4,\n \"method\": \"tools/list\"\n}\n```\n\n#### Why Notifications Matter\n\nThis notification system is crucial for several reasons:\n\n1. **Dynamic Environments**: Tools may come and go based on server state, external dependencies, or user permissions\n2. **Efficiency**: Clients don't need to poll for changes; they're notified when updates occur\n3. **Consistency**: Ensures clients always have accurate information about available server capabilities\n4. **Real-time Collaboration**: Enables responsive AI applications that can adapt to changing contexts\n\nThis notification pattern extends beyond tools to other MCP primitives, enabling comprehensive real-time synchronization between clients and servers.\n\n#### How This Works in AI Applications\n\nWhen the AI application receives a notification about changed tools, it immediately refreshes its tool registry and updates the LLM's available capabilities. This ensures that ongoing conversations always have access to the most current set of tools, and the LLM can dynamically adapt to new functionality as it becomes available.\n\n```python theme={null}\n# Pseudo-code for AI application notification handling\nasync def handle_tools_changed_notification(session):\n tools_response = await session.list_tools()\n app.update_available_tools(session, tools_response.tools)\n if app.conversation.is_active():\n app.conversation.notify_llm_of_new_capabilities()\n```",
      "updated_at": "1760788520.8599238",
      "filename": "architecture.md",
      "file_path": "architecture.md"
    },
    {
      "id": "md_authorization_8784292d",
      "url": "file://C:\\crawl\\authorization.md",
      "title": "Understanding Authorization in MCP",
      "content": "Understanding Authorization in MCP\n\nLearn how to implement secure authorization for MCP servers using OAuth 2.1 to protect sensitive resources and operations\n\nAuthorization in the Model Context Protocol (MCP) secures access to sensitive resources and operations exposed by MCP servers. If your MCP server handles user data or administrative actions, authorization ensures only permitted users can access its endpoints.\nMCP uses standardized authorization flows to build trust between MCP clients and MCP servers. Its design doesn't focus on one specific authorization or identity system, but rather follows the conventions outlined for OAuth 2.1. For detailed information, see the Authorization specification.\nWhen Should You Use Authorization?\nWhile authorization for MCP servers is optional, it is strongly recommended when:\n\nYour server accesses user-specific data (emails, documents, databases)\nYou need to audit who performed which actions\nYour server grants access to its APIs that require user consent\nYou're building for enterprise environments with strict access controls\nYou want to implement rate limiting or usage tracking per user\n\nAuthorization for Local MCP Servers\nFor MCP servers using the STDIO transport, you can use environment-based credentials or credentials provided by third-party libraries embedded directly in the MCP server instead. Because a STDIO-built MCP server runs locally, it has access to a range of flexible options when it comes to acquiring user credentials that may or may not rely on in-browser authentication and authorization flows.\nOAuth flows, in turn, are designed for HTTP-based transports where the MCP server is remotely-hosted and the client uses OAuth to establish that a user is authorized to access said remote server.\n\nThe Authorization Flow: Step by Step\nLet's walk through what happens when a client wants to connect to your protected MCP server:\n\n When your MCP client first tries to connect, your server responds with a 401 Unauthorized and tells the client where to find authorization information, captured in a Protected Resource Metadata (PRM) document. The document is hosted by the MCP server, follows a predictable path pattern, and is provided to the client in the resource_metadata parameter within the WWW-Authenticate header.\n```http theme={null}\nHTTP/1.1 401 Unauthorized\nWWW-Authenticate: Bearer realm=\"mcp\",\n resource_metadata=\"https://your-server.com/.well-known/oauth-protected-resource\"\n```\n\nThis tells the client that authorization is required for the MCP server and where to get the necessary information to kickstart the authorization flow.\n\n With the URI pointer to the PRM document, the client will fetch the metadata to learn about the authorization server, supported scopes, and other resource information. The data is typically encapsulated in a JSON blob, similar to the one below.\n```json theme={null}\n{\n \"resource\": \"https://your-server.com/mcp\",\n \"authorization_servers\": [\"https://auth.your-server.com\"],\n \"scopes_supported\": [\"mcp:tools\", \"mcp:resources\"]\n}\n```\n\nYou can see a more comprehensive example in [RFC 9278 Section 3.2](https://datatracker.ietf.org/doc/html/rfc9728#name-protected-resource-metadata-r).\n\n Next, the client discovers what the authorization server can do by fetching its metadata. If the PRM document lists more than one authorization server, the client can decide which one to use.\nWith an authorization server selected, the client will then construct a standard metadata URI and issue a request to the [OpenID Connect (OIDC) Discovery](https://openid.net/specs/openid-connect-discovery-1_0.html) or [OAuth 2.0 Auth Server Metadata](https://datatracker.ietf.org/doc/html/rfc8414) endpoints (depending on authorization server support)\nand retrieve another set of metadata properties that will allow it to know the endpoints it needs to complete the authorization flow.\n\n```json theme={null}\n{\n \"issuer\": \"https://auth.your-server.com\",\n \"authorization_endpoint\": \"https://auth.your-server.com/authorize\",\n \"token_endpoint\": \"https://auth.your-server.com/token\",\n \"registration_endpoint\": \"https://auth.your-server.com/register\"\n}\n```\n\n With all the metadata out of the way, the client now needs to make sure that it's registered with the authorization server. This can be done in two ways.\nFirst, the client can be **pre-registered** with a given authorization server, in which case it can have embedded client registration information that it uses to complete the authorization flow.\n\nAlternatively, the client can use **Dynamic Client Registration** (DCR) to dynamically register itself with the authorization server. The latter scenario requires the authorization server to support DCR. If the authorization server does support DCR, the client will send a request to the `registration_endpoint` with its information:\n\n```json theme={null}\n{\n \"client_name\": \"My MCP Client\",\n \"redirect_uris\": [\"http://localhost:3000/callback\"],\n \"grant_types\": [\"authorization_code\", \"refresh_token\"],\n \"response_types\": [\"code\"]\n}\n```\n\nIf the registration succeeds, the authorization server will return a JSON blob with client registration information.\n\n<Tip>\n **No DCR or Pre-Registration**\n\n In case a MCP client connects to a MCP server that doesn't use an authorization server that supports DCR and the client is not pre-registered with said authorization server, it's the responsibility of the client developer to provide an affordance for the end-user to enter client information manually.\n</Tip>\n\n The client will now need to open a browser to the /authorize endpoint, where the user can log in and grant the required permissions. The authorization server will then redirect back to the client with an authorization code that the client exchanges for tokens:\n```json theme={null}\n{\n \"access_token\": \"eyJhbGciOiJSUzI1NiIs...\",\n \"refresh_token\": \"def502...\",\n \"token_type\": \"Bearer\",\n \"expires_in\": 3600\n}\n```\n\nThe access token is what the client will use to authenticate requests to the MCP server. This step follows standard [OAuth 2.1 authorization code with PKCE](https://oauth.net/2/grant-types/authorization-code/) conventions.\n\n Finally, the client can make requests to your MCP server using the access token embedded in the Authorization header:\n```http theme={null}\nGET /mcp HTTP/1.1\nHost: your-server.com\nAuthorization: Bearer eyJhbGciOiJSUzI1NiIs...\n```\n\nThe MCP server will need to validate the token and process the request if the token is valid and has the required permissions.\n\nImplementation Example\nTo get started with a practical implementation, we will use a Keycloak authorization server hosted in a Docker container. Keycloak is an open-source authorization server that can be easily deployed locally for testing and experimentation.\nMake sure that you download and install Docker Desktop. We will need it to deploy Keycloak on our development machine.\nKeycloak Setup\nFrom your terminal application, run the following command to start the Keycloak container:\nbash theme={null}\ndocker run -p 127.0.0.1:8080:8080 -e KC_BOOTSTRAP_ADMIN_USERNAME=admin -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak start-dev\nThis command will pull the Keycloak container image locally and bootstrap the basic configuration. It will run on port 8080 and have an admin user with admin password.\n\nNot for Production\nThe configuration above may be suitable for testing and experimentation; however, you should never use it in production. Refer to the Configuring Keycloak for production guide for additional details on how to deploy the authorization server for scenarios that require reliability, security, and high availability.\n\nYou will be able to access the Keycloak authorization server from your browser at http://localhost:8080.\n\nWhen running with the default configuration, Keycloak will already support many of the capabilities that we need for MCP servers, including Dynamic Client Registration. You can check this by looking at the OIDC configuration, available at:\nhttp theme={null}\nhttp://localhost:8080/realms/master/.well-known/openid-configuration\nWe will also need to set up Keycloak to support our scopes and allow our host (local machine) to dynamically register clients, as the default policies restrict anonymous dynamic client registration.\nGo to Client scopes in the Keycloak dashboard and create a new mcp:tools scope. We will use this to access all of the tools on our MCP server.\n\nAfter creating the scope, make sure that you assign its type to Default and have flipped the Include in token scope switch, as this will be needed for token validation.\nLet's now also set up an audience for our Keycloak-issued tokens. An audience is important to configure because it embeds the intended destination directly into the issued access token. This helps your MCP server to verify that the token it got was actually meant for it rather than some other API. This is key to help avoid token passthrough scenarios.\nTo do this, open your mcp:tools client scope and click on Mappers, followed by Configure a new mapper. Select Audience.\n\nFor Name, use audience-config. Add a value for Included Custom Audience, set to http://localhost:3000. This will be the URI of our test server.\n\nNot for Production\nThe audience configuration above is meant for testing. For production scenarios, additional set-up and configuration will be required to ensure that audiences are properly constrained for issued tokens. Specifically, the audience needs to be based on the resource parameter passed from the client, not a fixed value.\n\nNow, navigate to Clients, then Client registration, and then Trusted Hosts. Disable the Client URIs Must Match setting and add the hosts from which you're testing. You can get your current host IP by running the ifconfig command on Linux or macOS, or ipconfig on Windows. You can see the IP address you need to add by looking at the keycloak logs for a line that looks like Failed to verify remote host : 192.168.215.1. Check that the IP address is associated with your host. This may be for a bridge network depending on your docker setup.\n\nGetting the Host\nIf you are running Keycloak from a container, you will also be able to see the host IP from the Terminal in the container logs.\n\nLastly, we need to register a new client that we can use with the MCP server itself to talk to Keycloak for things like token introspection. To do that:\n\nGo to Clients.\nClick Create client.\nGive your client a unique Client ID and click Next.\nEnable Client authentication and click Next.\nClick Save.\n\nWorth noting that token introspection is just one of the available approaches to validate tokens. This can also be done with the help of standalone libraries, specific to each language and platform.\nWhen you open the client details, go to Credentials and take note of the Client Secret.\n\nHandling Secrets\nNever embed client credentials directly in your code. We recommend using environment variables or specialized solutions for secret storage.\n\nWith Keycloak configured, every time the authorization flow is triggered, your MCP server will receive a token like this:\ntext theme={null}\neyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI1TjcxMGw1WW5MWk13WGZ1VlJKWGtCS3ZZMzZzb3JnRG5scmlyZ2tlTHlzIn0.eyJleHAiOjE3NTU1NDA4MTcsImlhdCI6MTc1NTU0MDc1NywiYXV0aF90aW1lIjoxNzU1NTM4ODg4LCJqdGkiOiJvbnJ0YWM6YjM0MDgwZmYtODQwNC02ODY3LTgxYmUtMTIzMWI1MDU5M2E4IiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy9tYXN0ZXIiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAiLCJzdWIiOiIzM2VkNmM2Yi1jNmUwLTQ5MjgtYTE2MS1mMmY2OWM3YTAzYjkiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiI3OTc1YTViNi04YjU5LTRhODUtOWNiYS04ZmFlYmRhYjg5NzQiLCJzaWQiOiI4ZjdlYzI3Ni0zNThmLTRjY2MtYjMxMy1kYjA4MjkwZjM3NmYiLCJzY29wZSI6Im1jcDp0b29scyJ9.P5xCRtXORly0R0EXjyqRCUx-z3J4uAOWNAvYtLPXroykZuVCCJ-K1haiQSwbURqfsVOMbL7jiV-sD6miuPzI1tmKOkN_Yct0Vp-azvj7U5rEj7U6tvPfMkg2Uj_jrIX0KOskyU2pVvGZ-5BgqaSvwTEdsGu_V3_E0xDuSBq2uj_wmhqiyTFm5lJ1WkM3Hnxxx1_AAnTj7iOKMFZ4VCwMmk8hhSC7clnDauORc0sutxiJuYUZzxNiNPkmNeQtMCGqWdP1igcbWbrfnNXhJ6NswBOuRbh97_QraET3hl-CNmyS6C72Xc0aOwR_uJ7xVSBTD02OaQ1JA6kjCATz30kGYg\nDecoded, it will look like this:\njson theme={null}\n{\n \"alg\": \"RS256\",\n \"typ\": \"JWT\",\n \"kid\": \"5N710l5YnLZMwXfuVRJXkBKvY36sorgDnlrirgkeLys\"\n}.{\n \"exp\": 1755540817,\n \"iat\": 1755540757,\n \"auth_time\": 1755538888,\n \"jti\": \"onrtac:b34080ff-8404-6867-81be-1231b50593a8\",\n \"iss\": \"http://localhost:8080/realms/master\",\n \"aud\": \"http://localhost:3000\",\n \"sub\": \"33ed6c6b-c6e0-4928-a161-f2f69c7a03b9\",\n \"typ\": \"Bearer\",\n \"azp\": \"7975a5b6-8b59-4a85-9cba-8faebdab8974\",\n \"sid\": \"8f7ec276-358f-4ccc-b313-db08290f376f\",\n \"scope\": \"mcp:tools\"\n}.[Signature]\n\nEmbedded Audience\nNotice the aud claim embedded in the token - it's currently set to be the URI of the test MCP server and it's inferred from the scope that we've previously configured. This will be important in our implementation to validate.\n\nMCP Server Setup\nWe will now set up our MCP server to use the locally-running Keycloak authorization server. Depending on your programming language preference, you can use one of the supported MCP SDKs.\nFor our testing purposes, we will create an extremely simple MCP server that exposes two tools - one for addition and another for multiplication. The server will require authorization to access these.\n\n You can see the complete TypeScript project in the sample repository.\nPrior to running the code below, ensure that you have a `.env` file with the following content:\n\n```env theme={null}\n# Server host/port\nHOST=localhost\nPORT=3000\n\n# Auth server location\nAUTH_HOST=localhost\nAUTH_PORT=8080\nAUTH_REALM=master\n\n# Keycloak OAuth client credentials\nOAUTH_CLIENT_ID=<YOUR_SERVER_CLIENT_ID>\nOAUTH_CLIENT_SECRET=<YOUR_SERVER_CLIENT_SECRET>\n```\n\n`OAUTH_CLIENT_ID` and `OAUTH_CLIENT_SECRET` are associated with the MCP server client we created earlier.\n\nIn addition to implementing the MCP authorization specification, the server below also does token introspection via Keycloak to make sure that the token it receives from the client is valid. It also implements basic logging to allow you to easily diagnose any issues.\n\n```typescript theme={null}\nimport \"dotenv/config\";\nimport express from \"express\";\nimport { randomUUID } from \"node:crypto\";\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport { isInitializeRequest } from \"@modelcontextprotocol/sdk/types.js\";\nimport { z } from \"zod\";\nimport cors from \"cors\";\nimport {\n mcpAuthMetadataRouter,\n getOAuthProtectedResourceMetadataUrl,\n} from \"@modelcontextprotocol/sdk/server/auth/router.js\";\nimport { requireBearerAuth } from \"@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js\";\nimport { OAuthMetadata } from \"@modelcontextprotocol/sdk/shared/auth.js\";\nimport { checkResourceAllowed } from \"@modelcontextprotocol/sdk/shared/auth-utils.js\";\nconst CONFIG = {\n host: process.env.HOST || \"localhost\",\n port: Number(process.env.PORT) || 3000,\n auth: {\n host: process.env.AUTH_HOST || process.env.HOST || \"localhost\",\n port: Number(process.env.AUTH_PORT) || 8080,\n realm: process.env.AUTH_REALM || \"master\",\n clientId: process.env.OAUTH_CLIENT_ID || \"mcp-server\",\n clientSecret: process.env.OAUTH_CLIENT_SECRET || \"\",\n },\n};\n\nfunction createOAuthUrls() {\n const authBaseUrl = new URL(\n `http://${CONFIG.auth.host}:${CONFIG.auth.port}/realms/${CONFIG.auth.realm}/`,\n );\n return {\n issuer: authBaseUrl.toString(),\n introspection_endpoint: new URL(\n \"protocol/openid-connect/token/introspect\",\n authBaseUrl,\n ).toString(),\n authorization_endpoint: new URL(\n \"protocol/openid-connect/auth\",\n authBaseUrl,\n ).toString(),\n token_endpoint: new URL(\n \"protocol/openid-connect/token\",\n authBaseUrl,\n ).toString(),\n };\n}\n\nfunction createRequestLogger() {\n return (req: any, res: any, next: any) => {\n const start = Date.now();\n res.on(\"finish\", () => {\n const ms = Date.now() - start;\n console.log(\n `${req.method} ${req.originalUrl} -> ${res.statusCode} ${ms}ms`,\n );\n });\n next();\n };\n}\n\nconst app = express();\n\napp.use(\n express.json({\n verify: (req: any, _res, buf) => {\n req.rawBody = buf?.toString() ?? \"\";\n },\n }),\n);\n\napp.use(\n cors({\n origin: \"*\",\n exposedHeaders: [\"Mcp-Session-Id\"],\n }),\n);\n\napp.use(createRequestLogger());\n\nconst mcpServerUrl = new URL(`http://${CONFIG.host}:${CONFIG.port}`);\nconst oauthUrls = createOAuthUrls();\n\nconst oauthMetadata: OAuthMetadata = {\n ...oauthUrls,\n response_types_supported: [\"code\"],\n};\n\nconst tokenVerifier = {\n verifyAccessToken: async (token: string) => {\n const endpoint = oauthMetadata.introspection_endpoint;\n\n if (!endpoint) {\n console.error(\"[auth] no introspection endpoint in metadata\");\n throw new Error(\"No token verification endpoint available in metadata\");\n }\n\n const params = new URLSearchParams({\n token: token,\n client_id: CONFIG.auth.clientId,\n });\n\n if (CONFIG.auth.clientSecret) {\n params.set(\"client_secret\", CONFIG.auth.clientSecret);\n }\n\n let response: Response;\n try {\n response = await fetch(endpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n },\n body: params.toString(),\n });\n } catch (e) {\n console.error(\"[auth] introspection fetch threw\", e);\n throw e;\n }\n\n if (!response.ok) {\n const txt = await response.text();\n console.error(\"[auth] introspection non-OK\", { status: response.status });\n\n try {\n const obj = JSON.parse(txt);\n console.log(JSON.stringify(obj, null, 2));\n } catch {\n console.error(txt);\n }\n throw new Error(`Invalid or expired token: ${txt}`);\n }\n\n let data: any;\n try {\n data = await response.json();\n } catch (e) {\n const txt = await response.text();\n console.error(\"[auth] failed to parse introspection JSON\", {\n error: String(e),\n body: txt,\n });\n throw e;\n }\n\n if (data.active === false) {\n throw new Error(\"Inactive token\");\n }\n\n if (!data.aud) {\n throw new Error(\"Resource indicator (aud) missing\");\n }\n\n const audiences: string[] = Array.isArray(data.aud) ? data.aud : [data.aud];\n const allowed = audiences.some((a) =>\n checkResourceAllowed({\n requestedResource: a,\n configuredResource: mcpServerUrl,\n }),\n );\n if (!allowed) {\n throw new Error(\n `None of the provided audiences are allowed. Expected ${mcpServerUrl}, got: ${audiences.join(\", \")}`,\n );\n }\n\n return {\n token,\n clientId: data.client_id,\n scopes: data.scope ? data.scope.split(\" \") : [],\n expiresAt: data.exp,\n };\n },\n};\napp.use(\n mcpAuthMetadataRouter({\n oauthMetadata,\n resourceServerUrl: mcpServerUrl,\n scopesSupported: [\"mcp:tools\"],\n resourceName: \"MCP Demo Server\",\n }),\n);\n\nconst authMiddleware = requireBearerAuth({\n verifier: tokenVerifier,\n requiredScopes: [],\n resourceMetadataUrl: getOAuthProtectedResourceMetadataUrl(mcpServerUrl),\n});\n\nconst transports: { [sessionId: string]: StreamableHTTPServerTransport } = {};\n\nfunction createMcpServer() {\n const server = new McpServer({\n name: \"example-server\",\n version: \"1.0.0\",\n });\n\n server.registerTool(\n \"add\",\n {\n title: \"Addition Tool\",\n description: \"Add two numbers together\",\n inputSchema: {\n a: z.number().describe(\"First number to add\"),\n b: z.number().describe(\"Second number to add\"),\n },\n },\n async ({ a, b }) => ({\n content: [{ type: \"text\", text: `${a} + ${b} = ${a + b}` }],\n }),\n );\n\n server.registerTool(\n \"multiply\",\n {\n title: \"Multiplication Tool\",\n description: \"Multiply two numbers together\",\n inputSchema: {\n x: z.number().describe(\"First number to multiply\"),\n y: z.number().describe(\"Second number to multiply\"),\n },\n },\n async ({ x, y }) => ({\n content: [{ type: \"text\", text: `${x} × ${y} = ${x * y}` }],\n }),\n );\n\n return server;\n}\n\nconst mcpPostHandler = async (req: express.Request, res: express.Response) => {\n const sessionId = req.headers[\"mcp-session-id\"] as string | undefined;\n let transport: StreamableHTTPServerTransport;\n\n if (sessionId && transports[sessionId]) {\n transport = transports[sessionId];\n } else if (!sessionId && isInitializeRequest(req.body)) {\n transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: () => randomUUID(),\n onsessioninitialized: (sessionId) => {\n transports[sessionId] = transport;\n },\n });\n\n transport.onclose = () => {\n if (transport.sessionId) {\n delete transports[transport.sessionId];\n }\n };\n\n const server = createMcpServer();\n await server.connect(transport);\n } else {\n res.status(400).json({\n jsonrpc: \"2.0\",\n error: {\n code: -32000,\n message: \"Bad Request: No valid session ID provided\",\n },\n id: null,\n });\n return;\n }\n\n await transport.handleRequest(req, res, req.body);\n};\n\nconst handleSessionRequest = async (\n req: express.Request,\n res: express.Response,\n) => {\n const sessionId = req.headers[\"mcp-session-id\"] as string | undefined;\n if (!sessionId || !transports[sessionId]) {\n res.status(400).send(\"Invalid or missing session ID\");\n return;\n }\n\n const transport = transports[sessionId];\n await transport.handleRequest(req, res);\n};\n\napp.post(\"/\", authMiddleware, mcpPostHandler);\napp.get(\"/\", authMiddleware, handleSessionRequest);\napp.delete(\"/\", authMiddleware, handleSessionRequest);\n\napp.listen(CONFIG.port, CONFIG.host, () => {\n console.log(`🚀 MCP Server running on ${mcpServerUrl.origin}`);\n console.log(`📡 MCP endpoint available at ${mcpServerUrl.origin}`);\n console.log(\n `🔐 OAuth metadata available at ${getOAuthProtectedResourceMetadataUrl(mcpServerUrl)}`,\n );\n});\n```\n\nWhen you run the server, you can add it to your MCP client, such as Visual Studio Code, by providing the MCP server endpoint.\n\nFor more details about implementing MCP servers in TypeScript, refer to the [TypeScript SDK documentation](https://github.com/modelcontextprotocol/typescript-sdk).\n\n You can see the complete Python project in the sample repository.\nTo simplify our authorization interaction, in Python scenarios we rely on [FastMCP](https://gofastmcp.com/getting-started/welcome). A lot of the conventions around authorization, like the endpoints and token validation logic, are consistent across languages, but some offer simpler ways in integrating them in production scenarios.\n\nPrior to writing the actual server, we need to set up our configuration in `config.py` - the contents are entirely based on your local server setup:\n\n```python theme={null}\n\"\"\"Configuration settings for the MCP auth server.\"\"\"\n\nimport os\nfrom typing import Optional\n\nclass Config:\n \"\"\"Configuration class that loads from environment variables with sensible defaults.\"\"\"\n\n # Server settings\n HOST: str = os.getenv(\"HOST\", \"localhost\")\n PORT: int = int(os.getenv(\"PORT\", \"3000\"))\n\n # Auth server settings\n AUTH_HOST: str = os.getenv(\"AUTH_HOST\", \"localhost\")\n AUTH_PORT: int = int(os.getenv(\"AUTH_PORT\", \"8080\"))\n AUTH_REALM: str = os.getenv(\"AUTH_REALM\", \"master\")\n\n # OAuth client settings\n OAUTH_CLIENT_ID: str = os.getenv(\"OAUTH_CLIENT_ID\", \"mcp-server\")\n OAUTH_CLIENT_SECRET: str = os.getenv(\"OAUTH_CLIENT_SECRET\", \"UO3rmozkFFkXr0QxPTkzZ0LMXDidIikB\")\n\n # Server settings\n MCP_SCOPE: str = os.getenv(\"MCP_SCOPE\", \"mcp:tools\")\n OAUTH_STRICT: bool = os.getenv(\"OAUTH_STRICT\", \"false\").lower() in (\"true\", \"1\", \"yes\")\n TRANSPORT: str = os.getenv(\"TRANSPORT\", \"streamable-http\")\n\n @property\n def server_url(self) -> str:\n \"\"\"Build the server URL.\"\"\"\n return f\"http://{self.HOST}:{self.PORT}\"\n\n @property\n def auth_base_url(self) -> str:\n \"\"\"Build the auth server base URL.\"\"\"\n return f\"http://{self.AUTH_HOST}:{self.AUTH_PORT}/realms/{self.AUTH_REALM}/\"\n\n def validate(self) -> None:\n \"\"\"Validate configuration.\"\"\"\n if self.TRANSPORT not in [\"sse\", \"streamable-http\"]:\n raise ValueError(f\"Invalid transport: {self.TRANSPORT}. Must be 'sse' or 'streamable-http'\")\n\n# Global configuration instance\nconfig = Config()\n\n```\n\nThe server implementation is as follows:\n\n```python theme={null}\nimport datetime\nimport logging\nfrom typing import Any\n\nfrom pydantic import AnyHttpUrl\n\nfrom mcp.server.auth.settings import AuthSettings\nfrom mcp.server.fastmcp.server import FastMCP\n\nfrom .config import config\nfrom .token_verifier import IntrospectionTokenVerifier\n\nlogger = logging.getLogger(__name__)\n\ndef create_oauth_urls() -> dict[str, str]:\n \"\"\"Create OAuth URLs based on configuration (Keycloak-style).\"\"\"\n from urllib.parse import urljoin\n\n auth_base_url = config.auth_base_url\n\n return {\n \"issuer\": auth_base_url,\n \"introspection_endpoint\": urljoin(auth_base_url, \"protocol/openid-connect/token/introspect\"),\n \"authorization_endpoint\": urljoin(auth_base_url, \"protocol/openid-connect/auth\"),\n \"token_endpoint\": urljoin(auth_base_url, \"protocol/openid-connect/token\"),\n }\n\ndef create_server() -> FastMCP:\n \"\"\"Create and configure the FastMCP server.\"\"\"\n\n config.validate()\n\n oauth_urls = create_oauth_urls()\n\n token_verifier = IntrospectionTokenVerifier(\n introspection_endpoint=oauth_urls[\"introspection_endpoint\"],\n server_url=config.server_url,\n client_id=config.OAUTH_CLIENT_ID,\n client_secret=config.OAUTH_CLIENT_SECRET,\n )\n\n app = FastMCP(\n name=\"MCP Resource Server\",\n instructions=\"Resource Server that validates tokens via Authorization Server introspection\",\n host=config.HOST,\n port=config.PORT,\n debug=True,\n streamable_http_path=\"/\",\n token_verifier=token_verifier,\n auth=AuthSettings(\n issuer_url=AnyHttpUrl(oauth_urls[\"issuer\"]),\n required_scopes=[config.MCP_SCOPE],\n resource_server_url=AnyHttpUrl(config.server_url),\n ),\n )\n\n @app.tool()\n async def add_numbers(a: float, b: float) -> dict[str, Any]:\n \"\"\"\n Add two numbers together.\n This tool demonstrates basic arithmetic operations with OAuth authentication.\n\n Args:\n a: The first number to add\n b: The second number to add\n \"\"\"\n result = a + b\n return {\n \"operation\": \"addition\",\n \"operand_a\": a,\n \"operand_b\": b,\n \"result\": result,\n \"timestamp\": datetime.datetime.now().isoformat()\n }\n\n @app.tool()\n async def multiply_numbers(x: float, y: float) -> dict[str, Any]:\n \"\"\"\n Multiply two numbers together.\n This tool demonstrates basic arithmetic operations with OAuth authentication.\n\n Args:\n x: The first number to multiply\n y: The second number to multiply\n \"\"\"\n result = x * y\n return {\n \"operation\": \"multiplication\",\n \"operand_x\": x,\n \"operand_y\": y,\n \"result\": result,\n \"timestamp\": datetime.datetime.now().isoformat()\n }\n\n return app\n\ndef main() -> int:\n \"\"\"\n Run the MCP Resource Server.\n\n This server:\n - Provides RFC 9728 Protected Resource Metadata\n - Validates tokens via Authorization Server introspection\n - Serves MCP tools requiring authentication\n\n Configuration is loaded from config.py and environment variables.\n \"\"\"\n logging.basicConfig(level=logging.INFO)\n\n try:\n config.validate()\n oauth_urls = create_oauth_urls()\n\n except ValueError as e:\n logger.error(\"Configuration error: %s\", e)\n return 1\n\n try:\n mcp_server = create_server()\n\n logger.info(\"Starting MCP Server on %s:%s\", config.HOST, config.PORT)\n logger.info(\"Authorization Server: %s\", oauth_urls[\"issuer\"])\n logger.info(\"Transport: %s\", config.TRANSPORT)\n\n mcp_server.run(transport=config.TRANSPORT)\n return 0\n\n except Exception:\n logger.exception(\"Server error\")\n return 1\n\nif __name__ == \"__main__\":\n exit(main())\n```\n\nLastly, the token verification logic is delegated entirely to `token_verifier.py`, ensuring that we can use the Keycloak introspection endpoint to verify the validity of any credential artifacts\n\n```python theme={null}\n\"\"\"Token verifier implementation using OAuth 2.0 Token Introspection (RFC 7662).\"\"\"\n\nimport logging\nfrom typing import Any\n\nfrom mcp.server.auth.provider import AccessToken, TokenVerifier\nfrom mcp.shared.auth_utils import check_resource_allowed, resource_url_from_server_url\n\nlogger = logging.getLogger(__name__)\n\nclass IntrospectionTokenVerifier(TokenVerifier):\n \"\"\"Token verifier that uses OAuth 2.0 Token Introspection (RFC 7662).\n \"\"\"\n\n def __init__(\n self,\n introspection_endpoint: str,\n server_url: str,\n client_id: str,\n client_secret: str,\n ):\n self.introspection_endpoint = introspection_endpoint\n self.server_url = server_url\n self.client_id = client_id\n self.client_secret = client_secret\n self.resource_url = resource_url_from_server_url(server_url)\n\n async def verify_token(self, token: str) -> AccessToken | None:\n \"\"\"Verify token via introspection endpoint.\"\"\"\n import httpx\n\n if not self.introspection_endpoint.startswith((\"https://\", \"http://localhost\", \"http://127.0.0.1\")):\n return None\n\n timeout = httpx.Timeout(10.0, connect=5.0)\n limits = httpx.Limits(max_connections=10, max_keepalive_connections=5)\n\n async with httpx.AsyncClient(\n timeout=timeout,\n limits=limits,\n verify=True,\n ) as client:\n try:\n form_data = {\n \"token\": token,\n \"client_id\": self.client_id,\n \"client_secret\": self.client_secret,\n }\n headers = {\"Content-Type\": \"application/x-www-form-urlencoded\"}\n\n response = await client.post(\n self.introspection_endpoint,\n data=form_data,\n headers=headers,\n )\n\n if response.status_code != 200:\n return None\n\n data = response.json()\n if not data.get(\"active\", False):\n return None\n\n if not self._validate_resource(data):\n return None\n\n return AccessToken(\n token=token,\n client_id=data.get(\"client_id\", \"unknown\"),\n scopes=data.get(\"scope\", \"\").split() if data.get(\"scope\") else [],\n expires_at=data.get(\"exp\"),\n resource=data.get(\"aud\"), # Include resource in token\n )\n\n except Exception as e:\n return None\n\n def _validate_resource(self, token_data: dict[str, Any]) -> bool:\n \"\"\"Validate token was issued for this resource server.\n\n Rules:\n - Reject if 'aud' missing.\n - Accept if any audience entry matches the derived resource URL.\n - Supports string or list forms per JWT spec.\n \"\"\"\n if not self.server_url or not self.resource_url:\n return False\n\n aud: list[str] | str | None = token_data.get(\"aud\")\n if isinstance(aud, list):\n return any(self._is_valid_resource(a) for a in aud)\n if isinstance(aud, str):\n return self._is_valid_resource(aud)\n return False\n\n def _is_valid_resource(self, resource: str) -> bool:\n \"\"\"Check if the given resource matches our server.\"\"\"\n return check_resource_allowed(self.resource_url, resource)\n```\n\nFor more details, see the [Python SDK documentation](https://github.com/modelcontextprotocol/python-sdk).\n\n You can see the complete C# project in the sample repository.\nTo set up authorization in your MCP server using the MCP C# SDK, you can lean on the standard ASP.NET Core builder pattern. Instead of using the introspection endpoint provided by Keycloak, we will use built-in ASP.NET Core capabilities for token validation.\n\n```csharp theme={null}\nusing Microsoft.AspNetCore.Authentication.JwtBearer;\nusing Microsoft.IdentityModel.Tokens;\nusing ModelContextProtocol.AspNetCore.Authentication;\nusing ProtectedMcpServer.Tools;\nusing System.Security.Claims;\n\nvar builder = WebApplication.CreateBuilder(args);\n\nvar serverUrl = \"http://localhost:3000/\";\nvar authorizationServerUrl = \"http://localhost:8080/realms/master/\";\n\nbuilder.Services.AddAuthentication(options =>\n{\n options.DefaultChallengeScheme = McpAuthenticationDefaults.AuthenticationScheme;\n options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;\n})\n.AddJwtBearer(options =>\n{\n options.Authority = authorizationServerUrl;\n var normalizedServerAudience = serverUrl.TrimEnd('/');\n options.TokenValidationParameters = new TokenValidationParameters\n {\n ValidIssuer = authorizationServerUrl,\n ValidAudiences = new[] { normalizedServerAudience, serverUrl },\n AudienceValidator = (audiences, securityToken, validationParameters) =>\n {\n if (audiences == null) return false;\n foreach (var aud in audiences)\n {\n if (string.Equals(aud.TrimEnd('/'), normalizedServerAudience, StringComparison.OrdinalIgnoreCase))\n {\n return true;\n }\n }\n return false;\n }\n };\n\n options.RequireHttpsMetadata = false; // Set to true in production\n\n options.Events = new JwtBearerEvents\n {\n OnTokenValidated = context =>\n {\n var name = context.Principal?.Identity?.Name ?? \"unknown\";\n var email = context.Principal?.FindFirstValue(\"preferred_username\") ?? \"unknown\";\n Console.WriteLine($\"Token validated for: {name} ({email})\");\n return Task.CompletedTask;\n },\n OnAuthenticationFailed = context =>\n {\n Console.WriteLine($\"Authentication failed: {context.Exception.Message}\");\n return Task.CompletedTask;\n },\n };\n})\n.AddMcp(options =>\n{\n options.ResourceMetadata = new()\n {\n Resource = new Uri(serverUrl),\n ResourceDocumentation = new Uri(\"https://docs.example.com/api/math\"),\n AuthorizationServers = { new Uri(authorizationServerUrl) },\n ScopesSupported = [\"mcp:tools\"]\n };\n});\n\nbuilder.Services.AddAuthorization();\n\nbuilder.Services.AddHttpContextAccessor();\nbuilder.Services.AddMcpServer()\n .WithTools<MathTools>()\n .WithHttpTransport();\n\nvar app = builder.Build();\n\napp.UseAuthentication();\napp.UseAuthorization();\n\napp.MapMcp().RequireAuthorization();\n\nConsole.WriteLine($\"Starting MCP server with authorization at {serverUrl}\");\nConsole.WriteLine($\"Using Keycloak server at {authorizationServerUrl}\");\nConsole.WriteLine($\"Protected Resource Metadata URL: {serverUrl}.well-known/oauth-protected-resource\");\nConsole.WriteLine(\"Exposed Math tools: Add, Multiply\");\nConsole.WriteLine(\"Press Ctrl+C to stop the server\");\n\napp.Run(serverUrl);\n```\n\nFor more details, see the [C# SDK documentation](https://github.com/modelcontextprotocol/csharp-sdk).\n\nTesting the MCP Server\nFor testing purposes, we will be using Visual Studio Code, but any client that supports MCP and the new authorization specification will fit.\nPress Cmd + Shift + P and select MCP: Add server.... Select HTTP and enter http://localhost:3000. Give the server a unique name to be used inside Visual Studio Code. In mcp.json you should now see an entry like this:\njson theme={null}\n\"my-mcp-server-18676652\": {\n \"url\": \"http://localhost:3000\",\n \"type\": \"http\"\n}\nOn connection, you will be taken to the browser, where you will be prompted to consent to Visual Studio Code having access to the mcp:tools scope.\n\nAfter consenting, you will see the tools listed right above the server entry in mcp.json.\n\nYou will be able to invoke individual tools with the help of the # sign in the chat view.\n\nCommon Pitfalls and How to Avoid Them\nFor comprehensive security guidance, including attack vectors, mitigation strategies, and implementation best practices, make sure to read through Security Best Practices. A few key issues are called out below.\n\nDo not implement token validation or authorization logic by yourself. Use off-the-shelf, well-tested, and secure libraries for things like token validation or authorization decisions. Doing everything from scratch means that you're more likely to implement things incorrectly unless you are a security expert.\nUse short-lived access tokens. Depending on the authorization server used, this setting might be customizable. We recommend to not use long-lived tokens - if a malicious actor steals them, they will be able to maintain their access for longer periods.\nAlways validate tokens. Just because your server received a token does not mean that the token is valid or that it's meant for your server. Always verify that what your MCP server is getting from the client matches the required constraints.\nStore tokens in secure, encrypted storage. In certain scenarios, you might need to cache tokens server-side. If that is the case, ensure that the storage has the right access controls and cannot be easily exfiltrated by malicious parties with access to your server. You should also implement robust cache eviction policies to ensure that your MCP server is not re-using expired or otherwise invalid tokens.\nEnforce HTTPS in production. Do not accept tokens or redirect callbacks over plain HTTP except for localhost during development.\nLeast-privilege scopes. Don't use catch‑all scopes. Split access per tool or capability where possible and verify required scopes per route/tool on the resource server.\nDon't log credentials. Never log Authorization headers, tokens, codes, or secrets. Scrub query strings and headers. Redact sensitive fields in structured logs.\nSeparate app vs. resource server credentials. Don't reuse your MCP server's client secret for end‑user flows. Store all secrets in a proper secret manager, not in source control.\nReturn proper challenges. On 401, include WWW-Authenticate with Bearer, realm, and resource_metadata so clients can discover how to authenticate.\nDCR (Dynamic Client Registration) controls. If enabled, be aware of constraints specific to your organization, such as trusted hosts, required vetting, and audited registrations. Unauthenticated DCR means that anyone can register any client with your authorization server.\nMulti‑tenant/realm mix-ups. Pin to a single issuer/tenant unless explicitly multi‑tenant. Reject tokens from other realms even if signed by the same authorization server.\nAudience/resource indicator misuse. Don't configure or accept generic audiences (like api) or unrelated resources. Require the audience/resource to match your configured server.\nError detail leakage. Return generic messages to clients, but log detailed reasons with correlation IDs internally to aid troubleshooting without exposing internals.\nSession identifier hardening. Treat Mcp-Session-Id as untrusted input; never tie authorization to it. Regenerate on auth changes and validate lifecycle server‑side.\n\nRelated Standards and Documentation\nMCP authorization builds on these well-established standards:\n\nOAuth 2.1: The core authorization framework\nRFC 8414: Authorization Server Metadata discovery\nRFC 7591: Dynamic Client Registration\nRFC 9728: Protected Resource Metadata\nRFC 8707: Resource Indicators\n\nFor additional details, refer to:\n\nAuthorization Specification\nSecurity Best Practices\nAvailable MCP SDKs\n\nUnderstanding these standards will help you implement authorization correctly and troubleshoot issues when they arise.",
      "updated_at": "1760788399.6907165",
      "filename": "authorization.md",
      "file_path": "authorization.md"
    },
    {
      "id": "md_build-client_2e39af9f",
      "url": "file://C:\\crawl\\build-client.md",
      "title": "Build an MCP client",
      "content": "Build an MCP client\n\nGet started building your own client that can integrate with all MCP servers.\n\nIn this tutorial, you'll learn how to build an LLM-powered chatbot client that connects to MCP servers.\nBefore you begin, it helps to have gone through our Build an MCP Server tutorial so you can understand how clients and servers communicate.\n\nYou can find the complete code for this tutorial here.\n## System Requirements\n\nBefore starting, ensure your system meets these requirements:\n\n* Mac or Windows computer\n* Latest Python version installed\n* Latest version of `uv` installed\n\n## Setting Up Your Environment\n\nFirst, create a new Python project with `uv`:\n\n<CodeGroup>\n ```bash macOS/Linux theme={null}\n # Create project directory\n uv init mcp-client\n cd mcp-client\n\n # Create virtual environment\n uv venv\n\n # Activate virtual environment\n source .venv/bin/activate\n\n # Install required packages\n uv add mcp anthropic python-dotenv\n\n # Remove boilerplate files\n rm main.py\n\n # Create our main file\n touch client.py\n ```\n\n ```powershell Windows theme={null}\n # Create project directory\n uv init mcp-client\n cd mcp-client\n\n # Create virtual environment\n uv venv\n\n # Activate virtual environment\n .venv\\Scripts\\activate\n\n # Install required packages\n uv add mcp anthropic python-dotenv\n\n # Remove boilerplate files\n del main.py\n\n # Create our main file\n new-item client.py\n ```\n</CodeGroup>\n\n## Setting Up Your API Key\n\nYou'll need an Anthropic API key from the [Anthropic Console](https://console.anthropic.com/settings/keys).\n\nCreate a `.env` file to store it:\n\n```bash theme={null}\necho \"ANTHROPIC_API_KEY=<your key here>\" > .env\n```\n\nAdd `.env` to your `.gitignore`:\n\n```bash theme={null}\necho \".env\" >> .gitignore\n```\n\n<Warning>\n Make sure you keep your `ANTHROPIC_API_KEY` secure!\n</Warning>\n\n## Creating the Client\n\n### Basic Client Structure\n\nFirst, let's set up our imports and create the basic client class:\n\n```python theme={null}\nimport asyncio\nfrom typing import Optional\nfrom contextlib import AsyncExitStack\n\nfrom mcp import ClientSession, StdioServerParameters\nfrom mcp.client.stdio import stdio_client\n\nfrom anthropic import Anthropic\nfrom dotenv import load_dotenv\n\nload_dotenv() # load environment variables from .env\n\nclass MCPClient:\n def __init__(self):\n # Initialize session and client objects\n self.session: Optional[ClientSession] = None\n self.exit_stack = AsyncExitStack()\n self.anthropic = Anthropic()\n # methods will go here\n```\n\n### Server Connection Management\n\nNext, we'll implement the method to connect to an MCP server:\n\n```python theme={null}\nasync def connect_to_server(self, server_script_path: str):\n \"\"\"Connect to an MCP server\n\n Args:\n server_script_path: Path to the server script (.py or .js)\n \"\"\"\n is_python = server_script_path.endswith('.py')\n is_js = server_script_path.endswith('.js')\n if not (is_python or is_js):\n raise ValueError(\"Server script must be a .py or .js file\")\n\n command = \"python\" if is_python else \"node\"\n server_params = StdioServerParameters(\n command=command,\n args=[server_script_path],\n env=None\n )\n\n stdio_transport = await self.exit_stack.enter_async_context(stdio_client(server_params))\n self.stdio, self.write = stdio_transport\n self.session = await self.exit_stack.enter_async_context(ClientSession(self.stdio, self.write))\n\n await self.session.initialize()\n\n # List available tools\n response = await self.session.list_tools()\n tools = response.tools\n print(\"\\nConnected to server with tools:\", [tool.name for tool in tools])\n```\n\n### Query Processing Logic\n\nNow let's add the core functionality for processing queries and handling tool calls:\n\n```python theme={null}\nasync def process_query(self, query: str) -> str:\n \"\"\"Process a query using Claude and available tools\"\"\"\n messages = [\n {\n \"role\": \"user\",\n \"content\": query\n }\n ]\n\n response = await self.session.list_tools()\n available_tools = [{\n \"name\": tool.name,\n \"description\": tool.description,\n \"input_schema\": tool.inputSchema\n } for tool in response.tools]\n\n # Initial Claude API call\n response = self.anthropic.messages.create(\n model=\"claude-3-5-sonnet-20241022\",\n max_tokens=1000,\n messages=messages,\n tools=available_tools\n )\n\n # Process response and handle tool calls\n final_text = []\n\n assistant_message_content = []\n for content in response.content:\n if content.type == 'text':\n final_text.append(content.text)\n assistant_message_content.append(content)\n elif content.type == 'tool_use':\n tool_name = content.name\n tool_args = content.input\n\n # Execute tool call\n result = await self.session.call_tool(tool_name, tool_args)\n final_text.append(f\"[Calling tool {tool_name} with args {tool_args}]\")\n\n assistant_message_content.append(content)\n messages.append({\n \"role\": \"assistant\",\n \"content\": assistant_message_content\n })\n messages.append({\n \"role\": \"user\",\n \"content\": [\n {\n \"type\": \"tool_result\",\n \"tool_use_id\": content.id,\n \"content\": result.content\n }\n ]\n })\n\n # Get next response from Claude\n response = self.anthropic.messages.create(\n model=\"claude-3-5-sonnet-20241022\",\n max_tokens=1000,\n messages=messages,\n tools=available_tools\n )\n\n final_text.append(response.content[0].text)\n\n return \"\\n\".join(final_text)\n```\n\n### Interactive Chat Interface\n\nNow we'll add the chat loop and cleanup functionality:\n\n```python theme={null}\nasync def chat_loop(self):\n \"\"\"Run an interactive chat loop\"\"\"\n print(\"\\nMCP Client Started!\")\n print(\"Type your queries or 'quit' to exit.\")\n\n while True:\n try:\n query = input(\"\\nQuery: \").strip()\n\n if query.lower() == 'quit':\n break\n\n response = await self.process_query(query)\n print(\"\\n\" + response)\n\n except Exception as e:\n print(f\"\\nError: {str(e)}\")\n\nasync def cleanup(self):\n \"\"\"Clean up resources\"\"\"\n await self.exit_stack.aclose()\n```\n\n### Main Entry Point\n\nFinally, we'll add the main execution logic:\n\n```python theme={null}\nasync def main():\n if len(sys.argv) < 2:\n print(\"Usage: python client.py <path_to_server_script>\")\n sys.exit(1)\n\n client = MCPClient()\n try:\n await client.connect_to_server(sys.argv[1])\n await client.chat_loop()\n finally:\n await client.cleanup()\n\nif __name__ == \"__main__\":\n import sys\n asyncio.run(main())\n```\n\nYou can find the complete `client.py` file [here](https://github.com/modelcontextprotocol/quickstart-resources/blob/main/mcp-client-python/client.py).\n\n## Key Components Explained\n\n### 1. Client Initialization\n\n* The `MCPClient` class initializes with session management and API clients\n* Uses `AsyncExitStack` for proper resource management\n* Configures the Anthropic client for Claude interactions\n\n### 2. Server Connection\n\n* Supports both Python and Node.js servers\n* Validates server script type\n* Sets up proper communication channels\n* Initializes the session and lists available tools\n\n### 3. Query Processing\n\n* Maintains conversation context\n* Handles Claude's responses and tool calls\n* Manages the message flow between Claude and tools\n* Combines results into a coherent response\n\n### 4. Interactive Interface\n\n* Provides a simple command-line interface\n* Handles user input and displays responses\n* Includes basic error handling\n* Allows graceful exit\n\n### 5. Resource Management\n\n* Proper cleanup of resources\n* Error handling for connection issues\n* Graceful shutdown procedures\n\n## Common Customization Points\n\n1. **Tool Handling**\n * Modify `process_query()` to handle specific tool types\n * Add custom error handling for tool calls\n * Implement tool-specific response formatting\n\n2. **Response Processing**\n * Customize how tool results are formatted\n * Add response filtering or transformation\n * Implement custom logging\n\n3. **User Interface**\n * Add a GUI or web interface\n * Implement rich console output\n * Add command history or auto-completion\n\n## Running the Client\n\nTo run your client with any MCP server:\n\n```bash theme={null}\nuv run client.py path/to/server.py # python server\nuv run client.py path/to/build/index.js # node server\n```\n\n<Note>\n If you're continuing [the weather tutorial from the server quickstart](https://github.com/modelcontextprotocol/quickstart-resources/tree/main/weather-server-python), your command might look something like this: `python client.py .../quickstart-resources/weather-server-python/weather.py`\n</Note>\n\nThe client will:\n\n1. Connect to the specified server\n2. List available tools\n3. Start an interactive chat session where you can:\n * Enter queries\n * See tool executions\n * Get responses from Claude\n\nHere's an example of what it should look like if connected to the weather server from the server quickstart:\n\n<Frame>\n <img src=\"https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/client-claude-cli-python.png?fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=686d6e0ae7c54f807827db111eaed7d4\" data-og-width=\"1932\" width=\"1932\" data-og-height=\"1739\" height=\"1739\" data-path=\"images/client-claude-cli-python.png\" data-optimize=\"true\" data-opv=\"3\" srcset=\"https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/client-claude-cli-python.png?w=280&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=48ff45c4ca51501589d9f20f060daa56 280w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/client-claude-cli-python.png?w=560&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=b35ca5d8a67c2f08efec9c6519efcfe2 560w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/client-claude-cli-python.png?w=840&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=51b8f5c7fa48db6ccd30aa9988a8c917 840w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/client-claude-cli-python.png?w=1100&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=9e1b01bc4c324a7e5100674f63f36b13 1100w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/client-claude-cli-python.png?w=1650&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=e3e961bd5b5506fed6c860f70df9bf9d 1650w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/client-claude-cli-python.png?w=2500&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=da01c2527db68cb0c99d29d20751a868 2500w\" />\n</Frame>\n\n## How It Works\n\nWhen you submit a query:\n\n1. The client gets the list of available tools from the server\n2. Your query is sent to Claude along with tool descriptions\n3. Claude decides which tools (if any) to use\n4. The client executes any requested tool calls through the server\n5. Results are sent back to Claude\n6. Claude provides a natural language response\n7. The response is displayed to you\n\n## Best practices\n\n1. **Error Handling**\n * Always wrap tool calls in try-catch blocks\n * Provide meaningful error messages\n * Gracefully handle connection issues\n\n2. **Resource Management**\n * Use `AsyncExitStack` for proper cleanup\n * Close connections when done\n * Handle server disconnections\n\n3. **Security**\n * Store API keys securely in `.env`\n * Validate server responses\n * Be cautious with tool permissions\n\n4. **Tool Names**\n * Tool names can be validated according to the format specified [here](/specification/draft/server/tools#tool-names)\n * If a tool name conforms to the specified format, it should not fail validation by an MCP client\n\n## Troubleshooting\n\n### Server Path Issues\n\n* Double-check the path to your server script is correct\n* Use the absolute path if the relative path isn't working\n* For Windows users, make sure to use forward slashes (/) or escaped backslashes (\\\\) in the path\n* Verify the server file has the correct extension (.py for Python or .js for Node.js)\n\nExample of correct path usage:\n\n```bash theme={null}\n# Relative path\nuv run client.py ./server/weather.py\n\n# Absolute path\nuv run client.py /Users/username/projects/mcp-server/weather.py\n\n# Windows path (either format works)\nuv run client.py C:/projects/mcp-server/weather.py\nuv run client.py C:\\\\projects\\\\mcp-server\\\\weather.py\n```\n\n### Response Timing\n\n* The first response might take up to 30 seconds to return\n* This is normal and happens while:\n * The server initializes\n * Claude processes the query\n * Tools are being executed\n* Subsequent responses are typically faster\n* Don't interrupt the process during this initial waiting period\n\n### Common Error Messages\n\nIf you see:\n\n* `FileNotFoundError`: Check your server path\n* `Connection refused`: Ensure the server is running and the path is correct\n* `Tool execution failed`: Verify the tool's required environment variables are set\n* `Timeout error`: Consider increasing the timeout in your client configuration\n\nYou can find the complete code for this tutorial here.\n## System Requirements\n\nBefore starting, ensure your system meets these requirements:\n\n* Mac or Windows computer\n* Node.js 17 or higher installed\n* Latest version of `npm` installed\n* Anthropic API key (Claude)\n\n## Setting Up Your Environment\n\nFirst, let's create and set up our project:\n\n<CodeGroup>\n ```bash macOS/Linux theme={null}\n # Create project directory\n mkdir mcp-client-typescript\n cd mcp-client-typescript\n\n # Initialize npm project\n npm init -y\n\n # Install dependencies\n npm install @anthropic-ai/sdk @modelcontextprotocol/sdk dotenv\n\n # Install dev dependencies\n npm install -D @types/node typescript\n\n # Create source file\n touch index.ts\n ```\n\n ```powershell Windows theme={null}\n # Create project directory\n md mcp-client-typescript\n cd mcp-client-typescript\n\n # Initialize npm project\n npm init -y\n\n # Install dependencies\n npm install @anthropic-ai/sdk @modelcontextprotocol/sdk dotenv\n\n # Install dev dependencies\n npm install -D @types/node typescript\n\n # Create source file\n new-item index.ts\n ```\n</CodeGroup>\n\nUpdate your `package.json` to set `type: \"module\"` and a build script:\n\n```json package.json theme={null}\n{\n \"type\": \"module\",\n \"scripts\": {\n \"build\": \"tsc && chmod 755 build/index.js\"\n }\n}\n```\n\nCreate a `tsconfig.json` in the root of your project:\n\n```json tsconfig.json theme={null}\n{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"module\": \"Node16\",\n \"moduleResolution\": \"Node16\",\n \"outDir\": \"./build\",\n \"rootDir\": \"./\",\n \"strict\": true,\n \"esModuleInterop\": true,\n \"skipLibCheck\": true,\n \"forceConsistentCasingInFileNames\": true\n },\n \"include\": [\"index.ts\"],\n \"exclude\": [\"node_modules\"]\n}\n```\n\n## Setting Up Your API Key\n\nYou'll need an Anthropic API key from the [Anthropic Console](https://console.anthropic.com/settings/keys).\n\nCreate a `.env` file to store it:\n\n```bash theme={null}\necho \"ANTHROPIC_API_KEY=<your key here>\" > .env\n```\n\nAdd `.env` to your `.gitignore`:\n\n```bash theme={null}\necho \".env\" >> .gitignore\n```\n\n<Warning>\n Make sure you keep your `ANTHROPIC_API_KEY` secure!\n</Warning>\n\n## Creating the Client\n\n### Basic Client Structure\n\nFirst, let's set up our imports and create the basic client class in `index.ts`:\n\n```typescript theme={null}\nimport { Anthropic } from \"@anthropic-ai/sdk\";\nimport {\n MessageParam,\n Tool,\n} from \"@anthropic-ai/sdk/resources/messages/messages.mjs\";\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { StdioClientTransport } from \"@modelcontextprotocol/sdk/client/stdio.js\";\nimport readline from \"readline/promises\";\nimport dotenv from \"dotenv\";\n\ndotenv.config();\n\nconst ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY;\nif (!ANTHROPIC_API_KEY) {\n throw new Error(\"ANTHROPIC_API_KEY is not set\");\n}\n\nclass MCPClient {\n private mcp: Client;\n private anthropic: Anthropic;\n private transport: StdioClientTransport | null = null;\n private tools: Tool[] = [];\n\n constructor() {\n this.anthropic = new Anthropic({\n apiKey: ANTHROPIC_API_KEY,\n });\n this.mcp = new Client({ name: \"mcp-client-cli\", version: \"1.0.0\" });\n }\n // methods will go here\n}\n```\n\n### Server Connection Management\n\nNext, we'll implement the method to connect to an MCP server:\n\n```typescript theme={null}\nasync connectToServer(serverScriptPath: string) {\n try {\n const isJs = serverScriptPath.endsWith(\".js\");\n const isPy = serverScriptPath.endsWith(\".py\");\n if (!isJs && !isPy) {\n throw new Error(\"Server script must be a .js or .py file\");\n }\n const command = isPy\n ? process.platform === \"win32\"\n ? \"python\"\n : \"python3\"\n : process.execPath;\n\n this.transport = new StdioClientTransport({\n command,\n args: [serverScriptPath],\n });\n await this.mcp.connect(this.transport);\n\n const toolsResult = await this.mcp.listTools();\n this.tools = toolsResult.tools.map((tool) => {\n return {\n name: tool.name,\n description: tool.description,\n input_schema: tool.inputSchema,\n };\n });\n console.log(\n \"Connected to server with tools:\",\n this.tools.map(({ name }) => name)\n );\n } catch (e) {\n console.log(\"Failed to connect to MCP server: \", e);\n throw e;\n }\n}\n```\n\n### Query Processing Logic\n\nNow let's add the core functionality for processing queries and handling tool calls:\n\n```typescript theme={null}\nasync processQuery(query: string) {\n const messages: MessageParam[] = [\n {\n role: \"user\",\n content: query,\n },\n ];\n\n const response = await this.anthropic.messages.create({\n model: \"claude-3-5-sonnet-20241022\",\n max_tokens: 1000,\n messages,\n tools: this.tools,\n });\n\n const finalText = [];\n\n for (const content of response.content) {\n if (content.type === \"text\") {\n finalText.push(content.text);\n } else if (content.type === \"tool_use\") {\n const toolName = content.name;\n const toolArgs = content.input as { [x: string]: unknown } | undefined;\n\n const result = await this.mcp.callTool({\n name: toolName,\n arguments: toolArgs,\n });\n finalText.push(\n `[Calling tool ${toolName} with args ${JSON.stringify(toolArgs)}]`\n );\n\n messages.push({\n role: \"user\",\n content: result.content as string,\n });\n\n const response = await this.anthropic.messages.create({\n model: \"claude-3-5-sonnet-20241022\",\n max_tokens: 1000,\n messages,\n });\n\n finalText.push(\n response.content[0].type === \"text\" ? response.content[0].text : \"\"\n );\n }\n }\n\n return finalText.join(\"\\n\");\n}\n```\n\n### Interactive Chat Interface\n\nNow we'll add the chat loop and cleanup functionality:\n\n```typescript theme={null}\nasync chatLoop() {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n try {\n console.log(\"\\nMCP Client Started!\");\n console.log(\"Type your queries or 'quit' to exit.\");\n\n while (true) {\n const message = await rl.question(\"\\nQuery: \");\n if (message.toLowerCase() === \"quit\") {\n break;\n }\n const response = await this.processQuery(message);\n console.log(\"\\n\" + response);\n }\n } finally {\n rl.close();\n }\n}\n\nasync cleanup() {\n await this.mcp.close();\n}\n```\n\n### Main Entry Point\n\nFinally, we'll add the main execution logic:\n\n```typescript theme={null}\nasync function main() {\n if (process.argv.length < 3) {\n console.log(\"Usage: node index.ts <path_to_server_script>\");\n return;\n }\n const mcpClient = new MCPClient();\n try {\n await mcpClient.connectToServer(process.argv[2]);\n await mcpClient.chatLoop();\n } finally {\n await mcpClient.cleanup();\n process.exit(0);\n }\n}\n\nmain();\n```\n\n## Running the Client\n\nTo run your client with any MCP server:\n\n```bash theme={null}\n# Build TypeScript\nnpm run build\n\n# Run the client\nnode build/index.js path/to/server.py # python server\nnode build/index.js path/to/build/index.js # node server\n```\n\n<Note>\n If you're continuing [the weather tutorial from the server quickstart](https://github.com/modelcontextprotocol/quickstart-resources/tree/main/weather-server-typescript), your command might look something like this: `node build/index.js .../quickstart-resources/weather-server-typescript/build/index.js`\n</Note>\n\n**The client will:**\n\n1. Connect to the specified server\n2. List available tools\n3. Start an interactive chat session where you can:\n * Enter queries\n * See tool executions\n * Get responses from Claude\n\n## How It Works\n\nWhen you submit a query:\n\n1. The client gets the list of available tools from the server\n2. Your query is sent to Claude along with tool descriptions\n3. Claude decides which tools (if any) to use\n4. The client executes any requested tool calls through the server\n5. Results are sent back to Claude\n6. Claude provides a natural language response\n7. The response is displayed to you\n\n## Best practices\n\n1. **Error Handling**\n * Use TypeScript's type system for better error detection\n * Wrap tool calls in try-catch blocks\n * Provide meaningful error messages\n * Gracefully handle connection issues\n\n2. **Security**\n * Store API keys securely in `.env`\n * Validate server responses\n * Be cautious with tool permissions\n\n## Troubleshooting\n\n### Server Path Issues\n\n* Double-check the path to your server script is correct\n* Use the absolute path if the relative path isn't working\n* For Windows users, make sure to use forward slashes (/) or escaped backslashes (\\\\) in the path\n* Verify the server file has the correct extension (.js for Node.js or .py for Python)\n\nExample of correct path usage:\n\n```bash theme={null}\n# Relative path\nnode build/index.js ./server/build/index.js\n\n# Absolute path\nnode build/index.js /Users/username/projects/mcp-server/build/index.js\n\n# Windows path (either format works)\nnode build/index.js C:/projects/mcp-server/build/index.js\nnode build/index.js C:\\\\projects\\\\mcp-server\\\\build\\\\index.js\n```\n\n### Response Timing\n\n* The first response might take up to 30 seconds to return\n* This is normal and happens while:\n * The server initializes\n * Claude processes the query\n * Tools are being executed\n* Subsequent responses are typically faster\n* Don't interrupt the process during this initial waiting period\n\n### Common Error Messages\n\nIf you see:\n\n* `Error: Cannot find module`: Check your build folder and ensure TypeScript compilation succeeded\n* `Connection refused`: Ensure the server is running and the path is correct\n* `Tool execution failed`: Verify the tool's required environment variables are set\n* `ANTHROPIC_API_KEY is not set`: Check your .env file and environment variables\n* `TypeError`: Ensure you're using the correct types for tool arguments\n\n This is a quickstart demo based on Spring AI MCP auto-configuration and boot starters.\n To learn how to create sync and async MCP Clients manually, consult the Java SDK Client documentation\n \nThis example demonstrates how to build an interactive chatbot that combines Spring AI's Model Context Protocol (MCP) with the [Brave Search MCP Server](https://github.com/modelcontextprotocol/servers-archived/tree/main/src/brave-search). The application creates a conversational interface powered by Anthropic's Claude AI model that can perform internet searches through Brave Search, enabling natural language interactions with real-time web data.\n[You can find the complete code for this tutorial here.](https://github.com/spring-projects/spring-ai-examples/tree/main/model-context-protocol/web-search/brave-chatbot)\n\n## System Requirements\n\nBefore starting, ensure your system meets these requirements:\n\n* Java 17 or higher\n* Maven 3.6+\n* npx package manager\n* Anthropic API key (Claude)\n* Brave Search API key\n\n## Setting Up Your Environment\n\n1. Install npx (Node Package eXecute):\n First, make sure to install [npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)\n and then run:\n\n ```bash theme={null}\n npm install -g npx\n ```\n\n2. Clone the repository:\n\n ```bash theme={null}\n git clone https://github.com/spring-projects/spring-ai-examples.git\n cd model-context-protocol/brave-chatbot\n ```\n\n3. Set up your API keys:\n\n ```bash theme={null}\n export ANTHROPIC_API_KEY='your-anthropic-api-key-here'\n export BRAVE_API_KEY='your-brave-api-key-here'\n ```\n\n4. Build the application:\n\n ```bash theme={null}\n ./mvnw clean install\n ```\n\n5. Run the application using Maven:\n ```bash theme={null}\n ./mvnw spring-boot:run\n ```\n\n<Warning>\n Make sure you keep your `ANTHROPIC_API_KEY` and `BRAVE_API_KEY` keys secure!\n</Warning>\n\n## How it Works\n\nThe application integrates Spring AI with the Brave Search MCP server through several components:\n\n### MCP Client Configuration\n\n1. Required dependencies in pom.xml:\n\n```xml theme={null}\n<dependency>\n <groupId>org.springframework.ai</groupId>\n <artifactId>spring-ai-starter-mcp-client</artifactId>\n</dependency>\n<dependency>\n <groupId>org.springframework.ai</groupId>\n <artifactId>spring-ai-starter-model-anthropic</artifactId>\n</dependency>\n```\n\n2. Application properties (application.yml):\n\n```yml theme={null}\nspring:\n ai:\n mcp:\n client:\n enabled: true\n name: brave-search-client\n version: 1.0.0\n type: SYNC\n request-timeout: 20s\n stdio:\n root-change-notification: true\n servers-configuration: classpath:/mcp-servers-config.json\n toolcallback:\n enabled: true\n anthropic:\n api-key: ${ANTHROPIC_API_KEY}\n```\n\nThis activates the `spring-ai-starter-mcp-client` to create one or more `McpClient`s based on the provided server configuration.\nThe `spring.ai.mcp.client.toolcallback.enabled=true` property enables the tool callback mechanism, that automatically registers all MCP tool as spring ai tools.\nIt is disabled by default.\n\n3. MCP Server Configuration (`mcp-servers-config.json`):\n\n```json theme={null}\n{\n \"mcpServers\": {\n \"brave-search\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@modelcontextprotocol/server-brave-search\"],\n \"env\": {\n \"BRAVE_API_KEY\": \"<PUT YOUR BRAVE API KEY>\"\n }\n }\n }\n}\n```\n\n### Chat Implementation\n\nThe chatbot is implemented using Spring AI's ChatClient with MCP tool integration:\n\n```java theme={null}\nvar chatClient = chatClientBuilder\n .defaultSystem(\"You are useful assistant, expert in AI and Java.\")\n .defaultToolCallbacks((Object[]) mcpToolAdapter.toolCallbacks())\n .defaultAdvisors(new MessageChatMemoryAdvisor(new InMemoryChatMemory()))\n .build();\n```\n\nKey features:\n\n* Uses Claude AI model for natural language understanding\n* Integrates Brave Search through MCP for real-time web search capabilities\n* Maintains conversation memory using InMemoryChatMemory\n* Runs as an interactive command-line application\n\n### Build and run\n\n```bash theme={null}\n./mvnw clean install\njava -jar ./target/ai-mcp-brave-chatbot-0.0.1-SNAPSHOT.jar\n```\n\nor\n\n```bash theme={null}\n./mvnw spring-boot:run\n```\n\nThe application will start an interactive chat session where you can ask questions. The chatbot will use Brave Search when it needs to find information from the internet to answer your queries.\n\nThe chatbot can:\n\n* Answer questions using its built-in knowledge\n* Perform web searches when needed using Brave Search\n* Remember context from previous messages in the conversation\n* Combine information from multiple sources to provide comprehensive answers\n\n### Advanced Configuration\n\nThe MCP client supports additional configuration options:\n\n* Client customization through `McpSyncClientCustomizer` or `McpAsyncClientCustomizer`\n* Multiple clients with multiple transport types: `STDIO` and `SSE` (Server-Sent Events)\n* Integration with Spring AI's tool execution framework\n* Automatic client initialization and lifecycle management\n\nFor WebFlux-based applications, you can use the WebFlux starter instead:\n\n```xml theme={null}\n<dependency>\n <groupId>org.springframework.ai</groupId>\n <artifactId>spring-ai-mcp-client-webflux-spring-boot-starter</artifactId>\n</dependency>\n```\n\nThis provides similar functionality but uses a WebFlux-based SSE transport implementation, recommended for production deployments.\n\nYou can find the complete code for this tutorial here.\n## System Requirements\n\nBefore starting, ensure your system meets these requirements:\n\n* Java 17 or higher\n* Anthropic API key (Claude)\n\n## Setting up your environment\n\nFirst, let's install `java` and `gradle` if you haven't already.\nYou can download `java` from [official Oracle JDK website](https://www.oracle.com/java/technologies/downloads/).\nVerify your `java` installation:\n\n```bash theme={null}\njava --version\n```\n\nNow, let's create and set up your project:\n\n<CodeGroup>\n ```bash macOS/Linux theme={null}\n # Create a new directory for our project\n mkdir kotlin-mcp-client\n cd kotlin-mcp-client\n\n # Initialize a new kotlin project\n gradle init\n ```\n\n ```powershell Windows theme={null}\n # Create a new directory for our project\n md kotlin-mcp-client\n cd kotlin-mcp-client\n # Initialize a new kotlin project\n gradle init\n ```\n</CodeGroup>\n\nAfter running `gradle init`, you will be presented with options for creating your project.\nSelect **Application** as the project type, **Kotlin** as the programming language, and **Java 17** as the Java version.\n\nAlternatively, you can create a Kotlin application using the [IntelliJ IDEA project wizard](https://kotlinlang.org/docs/jvm-get-started.html).\n\nAfter creating the project, add the following dependencies:\n\n<CodeGroup>\n ```kotlin build.gradle.kts theme={null}\n val mcpVersion = \"0.4.0\"\n val slf4jVersion = \"2.0.9\"\n val anthropicVersion = \"0.8.0\"\n\n dependencies {\n implementation(\"io.modelcontextprotocol:kotlin-sdk:$mcpVersion\")\n implementation(\"org.slf4j:slf4j-nop:$slf4jVersion\")\n implementation(\"com.anthropic:anthropic-java:$anthropicVersion\")\n }\n ```\n\n ```groovy build.gradle theme={null}\n def mcpVersion = '0.3.0'\n def slf4jVersion = '2.0.9'\n def anthropicVersion = '0.8.0'\n dependencies {\n implementation \"io.modelcontextprotocol:kotlin-sdk:$mcpVersion\"\n implementation \"org.slf4j:slf4j-nop:$slf4jVersion\"\n implementation \"com.anthropic:anthropic-java:$anthropicVersion\"\n }\n ```\n</CodeGroup>\n\nAlso, add the following plugins to your build script:\n\n<CodeGroup>\n ```kotlin build.gradle.kts theme={null}\n plugins {\n id(\"com.github.johnrengelman.shadow\") version \"8.1.1\"\n }\n ```\n\n ```groovy build.gradle theme={null}\n plugins {\n id 'com.github.johnrengelman.shadow' version '8.1.1'\n }\n ```\n</CodeGroup>\n\n## Setting up your API key\n\nYou'll need an Anthropic API key from the [Anthropic Console](https://console.anthropic.com/settings/keys).\n\nSet up your API key:\n\n```bash theme={null}\nexport ANTHROPIC_API_KEY='your-anthropic-api-key-here'\n```\n\n<Warning>\n Make sure your keep your `ANTHROPIC_API_KEY` secure!\n</Warning>\n\n## Creating the Client\n\n### Basic Client Structure\n\nFirst, let's create the basic client class:\n\n```kotlin theme={null}\nclass MCPClient : AutoCloseable {\n private val anthropic = AnthropicOkHttpClient.fromEnv()\n private val mcp: Client = Client(clientInfo = Implementation(name = \"mcp-client-cli\", version = \"1.0.0\"))\n private lateinit var tools: List<ToolUnion>\n\n // methods will go here\n\n override fun close() {\n runBlocking {\n mcp.close()\n anthropic.close()\n }\n }\n```\n\n### Server connection management\n\nNext, we'll implement the method to connect to an MCP server:\n\n```kotlin theme={null}\nsuspend fun connectToServer(serverScriptPath: String) {\n try {\n val command = buildList {\n when (serverScriptPath.substringAfterLast(\".\")) {\n \"js\" -> add(\"node\")\n \"py\" -> add(if (System.getProperty(\"os.name\").lowercase().contains(\"win\")) \"python\" else \"python3\")\n \"jar\" -> addAll(listOf(\"java\", \"-jar\"))\n else -> throw IllegalArgumentException(\"Server script must be a .js, .py or .jar file\")\n }\n add(serverScriptPath)\n }\n\n val process = ProcessBuilder(command).start()\n val transport = StdioClientTransport(\n input = process.inputStream.asSource().buffered(),\n output = process.outputStream.asSink().buffered()\n )\n\n mcp.connect(transport)\n\n val toolsResult = mcp.listTools()\n tools = toolsResult?.tools?.map { tool ->\n ToolUnion.ofTool(\n Tool.builder()\n .name(tool.name)\n .description(tool.description ?: \"\")\n .inputSchema(\n Tool.InputSchema.builder()\n .type(JsonValue.from(tool.inputSchema.type))\n .properties(tool.inputSchema.properties.toJsonValue())\n .putAdditionalProperty(\"required\", JsonValue.from(tool.inputSchema.required))\n .build()\n )\n .build()\n )\n } ?: emptyList()\n println(\"Connected to server with tools: ${tools.joinToString(\", \") { it.tool().get().name() }}\")\n } catch (e: Exception) {\n println(\"Failed to connect to MCP server: $e\")\n throw e\n }\n}\n```\n\nAlso create a helper function to convert from `JsonObject` to `JsonValue` for Anthropic:\n\n```kotlin theme={null}\nprivate fun JsonObject.toJsonValue(): JsonValue {\n val mapper = ObjectMapper()\n val node = mapper.readTree(this.toString())\n return JsonValue.fromJsonNode(node)\n}\n```\n\n### Query processing logic\n\nNow let's add the core functionality for processing queries and handling tool calls:\n\n```kotlin theme={null}\nprivate val messageParamsBuilder: MessageCreateParams.Builder = MessageCreateParams.builder()\n .model(Model.CLAUDE_3_5_SONNET_20241022)\n .maxTokens(1024)\n\nsuspend fun processQuery(query: String): String {\n val messages = mutableListOf(\n MessageParam.builder()\n .role(MessageParam.Role.USER)\n .content(query)\n .build()\n )\n\n val response = anthropic.messages().create(\n messageParamsBuilder\n .messages(messages)\n .tools(tools)\n .build()\n )\n\n val finalText = mutableListOf<String>()\n response.content().forEach { content ->\n when {\n content.isText() -> finalText.add(content.text().getOrNull()?.text() ?: \"\")\n\n content.isToolUse() -> {\n val toolName = content.toolUse().get().name()\n val toolArgs =\n content.toolUse().get()._input().convert(object : TypeReference<Map<String, JsonValue>>() {})\n\n val result = mcp.callTool(\n name = toolName,\n arguments = toolArgs ?: emptyMap()\n )\n finalText.add(\"[Calling tool $toolName with args $toolArgs]\")\n\n messages.add(\n MessageParam.builder()\n .role(MessageParam.Role.USER)\n .content(\n \"\"\"\n \"type\": \"tool_result\",\n \"tool_name\": $toolName,\n \"result\": ${result?.content?.joinToString(\"\\n\") { (it as TextContent).text ?: \"\" }}\n \"\"\".trimIndent()\n )\n .build()\n )\n\n val aiResponse = anthropic.messages().create(\n messageParamsBuilder\n .messages(messages)\n .build()\n )\n\n finalText.add(aiResponse.content().first().text().getOrNull()?.text() ?: \"\")\n }\n }\n }\n\n return finalText.joinToString(\"\\n\", prefix = \"\", postfix = \"\")\n}\n```\n\n### Interactive chat\n\nWe'll add the chat loop:\n\n```kotlin theme={null}\nsuspend fun chatLoop() {\n println(\"\\nMCP Client Started!\")\n println(\"Type your queries or 'quit' to exit.\")\n\n while (true) {\n print(\"\\nQuery: \")\n val message = readLine() ?: break\n if (message.lowercase() == \"quit\") break\n val response = processQuery(message)\n println(\"\\n$response\")\n }\n}\n```\n\n### Main entry point\n\nFinally, we'll add the main execution function:\n\n```kotlin theme={null}\nfun main(args: Array<String>) = runBlocking {\n if (args.isEmpty()) throw IllegalArgumentException(\"Usage: java -jar <your_path>/build/libs/kotlin-mcp-client-0.1.0-all.jar <path_to_server_script>\")\n val serverPath = args.first()\n val client = MCPClient()\n client.use {\n client.connectToServer(serverPath)\n client.chatLoop()\n }\n}\n```\n\n## Running the client\n\nTo run your client with any MCP server:\n\n```bash theme={null}\n./gradlew build\n\n# Run the client\njava -jar build/libs/<your-jar-name>.jar path/to/server.jar # jvm server\njava -jar build/libs/<your-jar-name>.jar path/to/server.py # python server\njava -jar build/libs/<your-jar-name>.jar path/to/build/index.js # node server\n```\n\n<Note>\n If you're continuing the weather tutorial from the server quickstart, your command might look something like this: `java -jar build/libs/kotlin-mcp-client-0.1.0-all.jar .../samples/weather-stdio-server/build/libs/weather-stdio-server-0.1.0-all.jar`\n</Note>\n\n**The client will:**\n\n1. Connect to the specified server\n2. List available tools\n3. Start an interactive chat session where you can:\n * Enter queries\n * See tool executions\n * Get responses from Claude\n\n## How it works\n\nHere's a high-level workflow schema:\n\n```mermaid theme={null}\n---\nconfig:\n theme: neutral\n---\nsequenceDiagram\n actor User\n participant Client\n participant Claude\n participant MCP_Server as MCP Server\n participant Tools\n\n User->>Client: Send query\n Client<<->>MCP_Server: Get available tools\n Client->>Claude: Send query with tool descriptions\n Claude-->>Client: Decide tool execution\n Client->>MCP_Server: Request tool execution\n MCP_Server->>Tools: Execute chosen tools\n Tools-->>MCP_Server: Return results\n MCP_Server-->>Client: Send results\n Client->>Claude: Send tool results\n Claude-->>Client: Provide final response\n Client-->>User: Display response\n```\n\nWhen you submit a query:\n\n1. The client gets the list of available tools from the server\n2. Your query is sent to Claude along with tool descriptions\n3. Claude decides which tools (if any) to use\n4. The client executes any requested tool calls through the server\n5. Results are sent back to Claude\n6. Claude provides a natural language response\n7. The response is displayed to you\n\n## Best practices\n\n1. **Error Handling**\n * Leverage Kotlin's type system to model errors explicitly\n * Wrap external tool and API calls in `try-catch` blocks when exceptions are possible\n * Provide clear and meaningful error messages\n * Handle network timeouts and connection issues gracefully\n\n2. **Security**\n * Store API keys and secrets securely in `local.properties`, environment variables, or secret managers\n * Validate all external responses to avoid unexpected or unsafe data usage\n * Be cautious with permissions and trust boundaries when using tools\n\n## Troubleshooting\n\n### Server Path Issues\n\n* Double-check the path to your server script is correct\n* Use the absolute path if the relative path isn't working\n* For Windows users, make sure to use forward slashes (/) or escaped backslashes (\\\\) in the path\n* Make sure that the required runtime is installed (java for Java, npm for Node.js, or uv for Python)\n* Verify the server file has the correct extension (.jar for Java, .js for Node.js or .py for Python)\n\nExample of correct path usage:\n\n```bash theme={null}\n# Relative path\njava -jar build/libs/client.jar ./server/build/libs/server.jar\n\n# Absolute path\njava -jar build/libs/client.jar /Users/username/projects/mcp-server/build/libs/server.jar\n\n# Windows path (either format works)\njava -jar build/libs/client.jar C:/projects/mcp-server/build/libs/server.jar\njava -jar build/libs/client.jar C:\\\\projects\\\\mcp-server\\\\build\\\\libs\\\\server.jar\n```\n\n### Response Timing\n\n* The first response might take up to 30 seconds to return\n* This is normal and happens while:\n * The server initializes\n * Claude processes the query\n * Tools are being executed\n* Subsequent responses are typically faster\n* Don't interrupt the process during this initial waiting period\n\n### Common Error Messages\n\nIf you see:\n\n* `Connection refused`: Ensure the server is running and the path is correct\n* `Tool execution failed`: Verify the tool's required environment variables are set\n* `ANTHROPIC_API_KEY is not set`: Check your environment variables\n\nYou can find the complete code for this tutorial here.\n## System Requirements\n\nBefore starting, ensure your system meets these requirements:\n\n* .NET 8.0 or higher\n* Anthropic API key (Claude)\n* Windows, Linux, or macOS\n\n## Setting up your environment\n\nFirst, create a new .NET project:\n\n```bash theme={null}\ndotnet new console -n QuickstartClient\ncd QuickstartClient\n```\n\nThen, add the required dependencies to your project:\n\n```bash theme={null}\ndotnet add package ModelContextProtocol --prerelease\ndotnet add package Anthropic.SDK\ndotnet add package Microsoft.Extensions.Hosting\ndotnet add package Microsoft.Extensions.AI\n```\n\n## Setting up your API key\n\nYou'll need an Anthropic API key from the [Anthropic Console](https://console.anthropic.com/settings/keys).\n\n```bash theme={null}\ndotnet user-secrets init\ndotnet user-secrets set \"ANTHROPIC_API_KEY\" \"<your key here>\"\n```\n\n## Creating the Client\n\n### Basic Client Structure\n\nFirst, let's setup the basic client class in the file `Program.cs`:\n\n```csharp theme={null}\nusing Anthropic.SDK;\nusing Microsoft.Extensions.AI;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Hosting;\nusing ModelContextProtocol.Client;\nusing ModelContextProtocol.Protocol.Transport;\n\nvar builder = Host.CreateApplicationBuilder(args);\n\nbuilder.Configuration\n .AddEnvironmentVariables()\n .AddUserSecrets<Program>();\n```\n\nThis creates the beginnings of a .NET console application that can read the API key from user secrets.\n\nNext, we'll setup the MCP Client:\n\n```csharp theme={null}\nvar (command, arguments) = GetCommandAndArguments(args);\n\nvar clientTransport = new StdioClientTransport(new()\n{\n Name = \"Demo Server\",\n Command = command,\n Arguments = arguments,\n});\n\nawait using var mcpClient = await McpClientFactory.CreateAsync(clientTransport);\n\nvar tools = await mcpClient.ListToolsAsync();\nforeach (var tool in tools)\n{\n Console.WriteLine($\"Connected to server with tools: {tool.Name}\");\n}\n```\n\nAdd this function at the end of the `Program.cs` file:\n\n```csharp theme={null}\nstatic (string command, string[] arguments) GetCommandAndArguments(string[] args)\n{\n return args switch\n {\n [var script] when script.EndsWith(\".py\") => (\"python\", args),\n [var script] when script.EndsWith(\".js\") => (\"node\", args),\n [var script] when Directory.Exists(script) || (File.Exists(script) && script.EndsWith(\".csproj\")) => (\"dotnet\", [\"run\", \"--project\", script, \"--no-build\"]),\n _ => throw new NotSupportedException(\"An unsupported server script was provided. Supported scripts are .py, .js, or .csproj\")\n };\n}\n```\n\nThis creates an MCP client that will connect to a server that is provided as a command line argument. It then lists the available tools from the connected server.\n\n### Query processing logic\n\nNow let's add the core functionality for processing queries and handling tool calls:\n\n```csharp theme={null}\nusing var anthropicClient = new AnthropicClient(new APIAuthentication(builder.Configuration[\"ANTHROPIC_API_KEY\"]))\n .Messages\n .AsBuilder()\n .UseFunctionInvocation()\n .Build();\n\nvar options = new ChatOptions\n{\n MaxOutputTokens = 1000,\n ModelId = \"claude-3-5-sonnet-20241022\",\n Tools = [.. tools]\n};\n\nConsole.ForegroundColor = ConsoleColor.Green;\nConsole.WriteLine(\"MCP Client Started!\");\nConsole.ResetColor();\n\nPromptForInput();\nwhile(Console.ReadLine() is string query && !\"exit\".Equals(query, StringComparison.OrdinalIgnoreCase))\n{\n if (string.IsNullOrWhiteSpace(query))\n {\n PromptForInput();\n continue;\n }\n\n await foreach (var message in anthropicClient.GetStreamingResponseAsync(query, options))\n {\n Console.Write(message);\n }\n Console.WriteLine();\n\n PromptForInput();\n}\n\nstatic void PromptForInput()\n{\n Console.WriteLine(\"Enter a command (or 'exit' to quit):\");\n Console.ForegroundColor = ConsoleColor.Cyan;\n Console.Write(\"> \");\n Console.ResetColor();\n}\n```\n\n## Key Components Explained\n\n### 1. Client Initialization\n\n* The client is initialized using `McpClientFactory.CreateAsync()`, which sets up the transport type and command to run the server.\n\n### 2. Server Connection\n\n* Supports Python, Node.js, and .NET servers.\n* The server is started using the command specified in the arguments.\n* Configures to use stdio for communication with the server.\n* Initializes the session and available tools.\n\n### 3. Query Processing\n\n* Leverages [Microsoft.Extensions.AI](https://learn.microsoft.com/dotnet/ai/ai-extensions) for the chat client.\n* Configures the `IChatClient` to use automatic tool (function) invocation.\n* The client reads user input and sends it to the server.\n* The server processes the query and returns a response.\n* The response is displayed to the user.\n\n## Running the Client\n\nTo run your client with any MCP server:\n\n```bash theme={null}\ndotnet run -- path/to/server.csproj # dotnet server\ndotnet run -- path/to/server.py # python server\ndotnet run -- path/to/server.js # node server\n```\n\n<Note>\n If you're continuing the weather tutorial from the server quickstart, your command might look something like this: `dotnet run -- path/to/QuickstartWeatherServer`.\n</Note>\n\nThe client will:\n\n1. Connect to the specified server\n2. List available tools\n3. Start an interactive chat session where you can:\n * Enter queries\n * See tool executions\n * Get responses from Claude\n4. Exit the session when done\n\nHere's an example of what it should look like it connected to a weather server quickstart:\n\n<Frame>\n <img src=\"https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-dotnet-client.png?fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=fcf28dde150d6db879402ad8150c6b23\" data-og-width=\"1115\" width=\"1115\" data-og-height=\"666\" height=\"666\" data-path=\"images/quickstart-dotnet-client.png\" data-optimize=\"true\" data-opv=\"3\" srcset=\"https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-dotnet-client.png?w=280&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=0c82cdfe1350b4a924a44d7beaa39f70 280w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-dotnet-client.png?w=560&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=4fd6f3ed867741b44ae12940788be646 560w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-dotnet-client.png?w=840&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=1b5fcfaf8b63b9ea71bf36aa20388a28 840w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-dotnet-client.png?w=1100&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=cb969889d05ec8771c12b887f2940c7d 1100w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-dotnet-client.png?w=1650&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=81b2cb62f60a9f3afb2d66cf3ee3df79 1650w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-dotnet-client.png?w=2500&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=ac9271a3dd0d7b424bb390ad0c31e14e 2500w\" />\n</Frame>\n\nNext steps\n\n Check out our gallery of official MCP servers and implementations\n \n\n View the list of clients that support MCP integrations",
      "updated_at": "1760788520.8554032",
      "filename": "build-client.md",
      "file_path": "build-client.md"
    },
    {
      "id": "md_client-concepts_66f702b4",
      "url": "file://C:\\crawl\\client-concepts.md",
      "title": "Understanding MCP clients",
      "content": "Understanding MCP clients\nMCP clients are instantiated by host applications to communicate with particular MCP servers. The host application, like Claude.ai or an IDE, manages the overall user experience and coordinates multiple clients. Each client handles one direct communication with one server.\nUnderstanding the distinction is important: the host is the application users interact with, while clients are the protocol-level components that enable server connections.\nCore Client Features\nIn addition to making use of context provided by servers, clients may provide several features to servers. These client features allow server authors to build richer interactions.\n| Feature | Explanation | Example |\n| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |\n| Sampling | Sampling allows servers to request LLM completions through the client, enabling an agentic workflow. This approach puts the client in complete control of user permissions and security measures. | A server for booking travel may send a list of flights to an LLM and request that the LLM pick the best flight for the user. |\n| Roots | Roots allow clients to specify which directories servers should focus on, communicating intended scope through a coordination mechanism. | A server for booking travel may be given access to a specific directory, from which it can read a user's calendar. |\n| Elicitation | Elicitation enables servers to request specific information from users during interactions, providing a structured way for servers to gather information on demand. | A server booking travel may ask for the user's preferences on airplane seats, room type or their contact number to finalise a booking. |\nElicitation\nElicitation enables servers to request specific information from users during interactions, creating more dynamic and responsive workflows.\nOverview\nElicitation provides a structured way for servers to gather necessary information on demand. Instead of requiring all information up front or failing when data is missing, servers can pause their operations to request specific inputs from users. This creates more flexible interactions where servers adapt to user needs rather than following rigid patterns.\nElicitation flow:\n```mermaid theme={null}\nsequenceDiagram\n participant User\n participant Client\n participant Server\nNote over Server,Client: Server initiates elicitation\nServer->>Client: elicitation/create\n\nNote over Client,User: Human interaction\nClient->>User: Present elicitation UI\nUser-->>Client: Provide requested information\n\nNote over Server,Client: Complete request\nClient-->>Server: Return user response\n\nNote over Server: Continue processing with new information\n\n```\nThe flow enables dynamic information gathering. Servers can request specific data when needed, users provide information through appropriate UI, and servers continue processing with the newly acquired context.\nElicitation components example:\ntypescript theme={null}\n{\n method: \"elicitation/requestInput\",\n params: {\n message: \"Please confirm your Barcelona vacation booking details:\",\n schema: {\n type: \"object\",\n properties: {\n confirmBooking: {\n type: \"boolean\",\n description: \"Confirm the booking (Flights + Hotel = $3,000)\"\n },\n seatPreference: {\n type: \"string\",\n enum: [\"window\", \"aisle\", \"no preference\"],\n description: \"Preferred seat type for flights\"\n },\n roomType: {\n type: \"string\",\n enum: [\"sea view\", \"city view\", \"garden view\"],\n description: \"Preferred room type at hotel\"\n },\n travelInsurance: {\n type: \"boolean\",\n default: false,\n description: \"Add travel insurance ($150)\"\n }\n },\n required: [\"confirmBooking\"]\n }\n }\n}\nExample: Holiday Booking Approval\nA travel booking server demonstrates elicitation's power through the final booking confirmation process. When a user has selected their ideal vacation package to Barcelona, the server needs to gather final approval and any missing details before proceeding.\nThe server elicits booking confirmation with a structured request that includes the trip summary (Barcelona flights June 15-22, beachfront hotel, total \\$3,000) and fields for any additional preferences—such as seat selection, room type, or travel insurance options.\nAs the booking progresses, the server elicits contact information needed to complete the reservation. It might ask for traveler details for flight bookings, special requests for the hotel, or emergency contact information.\nUser Interaction Model\nElicitation interactions are designed to be clear, contextual, and respectful of user autonomy:\nRequest presentation: Clients display elicitation requests with clear context about which server is asking, why the information is needed, and how it will be used. The request message explains the purpose while the schema provides structure and validation.\nResponse options: Users can provide the requested information through appropriate UI controls (text fields, dropdowns, checkboxes), decline to provide information with optional explanation, or cancel the entire operation. Clients validate responses against the provided schema before returning them to servers.\nPrivacy considerations: Elicitation never requests passwords or API keys. Clients warn about suspicious requests and let users review data before sending.\nRoots\nRoots define filesystem boundaries for server operations, allowing clients to specify which directories servers should focus on.\nOverview\nRoots are a mechanism for clients to communicate filesystem access boundaries to servers. They consist of file URIs that indicate directories where servers can operate, helping servers understand the scope of available files and folders. While roots communicate intended boundaries, they do not enforce security restrictions. Actual security must be enforced at the operating system level, via file permissions and/or sandboxing.\nRoot structure:\njson theme={null}\n{\n \"uri\": \"file:///Users/agent/travel-planning\",\n \"name\": \"Travel Planning Workspace\"\n}\nRoots are exclusively filesystem paths and always use the file:// URI scheme. They help servers understand project boundaries, workspace organization, and accessible directories. The roots list can be updated dynamically as users work with different projects or folders, with servers receiving notifications through roots/list_changed when boundaries change.\nExample: Travel Planning Workspace\nA travel agent working with multiple client trips benefits from roots to organize filesystem access. Consider a workspace with different directories for various aspects of travel planning.\nThe client provides filesystem roots to the travel planning server:\n\nfile:///Users/agent/travel-planning - Main workspace containing all travel files\nfile:///Users/agent/travel-templates - Reusable itinerary templates and resources\nfile:///Users/agent/client-documents - Client passports and travel documents\n\nWhen the agent creates a Barcelona itinerary, well-behaved servers respect these boundaries—accessing templates, saving the new itinerary, and referencing client documents within the specified roots. Servers typically access files within roots by using relative paths from the root directories or by utilizing file search tools that respect the root boundaries.\nIf the agent opens an archive folder like file:///Users/agent/archive/2023-trips, the client updates the roots list via roots/list_changed.\nFor a complete implementation of a server that respects roots, see the filesystem server in the official servers repository.\nDesign Philosophy\nRoots serve as a coordination mechanism between clients and servers, not a security boundary. The specification requires that servers \"SHOULD respect root boundaries,\" and not that they \"MUST enforce\" them, because servers run code the client cannot control.\nRoots work best when servers are trusted or vetted, users understand their advisory nature, and the goal is preventing accidents rather than stopping malicious behavior. They excel at context scoping (telling servers where to focus), accident prevention (helping well-behaved servers stay in bounds), and workflow organization (such as managing project boundaries automatically).\nUser Interaction Model\nRoots are typically managed automatically by host applications based on user actions, though some applications may expose manual root management:\nAutomatic root detection: When users open folders, clients automatically expose them as roots. Opening a travel workspace allows the client to expose that directory as a root, helping servers understand which itineraries and documents are in scope for the current work.\nManual root configuration: Advanced users can specify roots through configuration. For example, adding /travel-templates for reusable resources while excluding directories with financial records.\nSampling\nSampling allows servers to request language model completions through the client, enabling agentic behaviors while maintaining security and user control.\nOverview\nSampling enables servers to perform AI-dependent tasks without directly integrating with or paying for AI models. Instead, servers can request that the client—which already has AI model access—handle these tasks on their behalf. This approach puts the client in complete control of user permissions and security measures. Because sampling requests occur within the context of other operations—like a tool analyzing data—and are processed as separate model calls, they maintain clear boundaries between different contexts, allowing for more efficient use of the context window.\nSampling flow:\n```mermaid theme={null}\nsequenceDiagram\n participant LLM\n participant User\n participant Client\n participant Server\nNote over Server,Client: Server initiates sampling\nServer->>Client: sampling/createMessage\n\nNote over Client,User: Human-in-the-loop review\nClient->>User: Present request for approval\nUser-->>Client: Review and approve/modify\n\nNote over Client,LLM: Model interaction\nClient->>LLM: Forward approved request\nLLM-->>Client: Return generation\n\nNote over Client,User: Response review\nClient->>User: Present response for approval\nUser-->>Client: Review and approve/modify\n\nNote over Server,Client: Complete request\nClient-->>Server: Return approved response\n\n```\nThe flow ensures security through multiple human-in-the-loop checkpoints. Users review and can modify both the initial request and the generated response before it returns to the server.\nRequest parameters example:\ntypescript theme={null}\n{\n messages: [\n {\n role: \"user\",\n content: \"Analyze these flight options and recommend the best choice:\\n\" +\n \"[47 flights with prices, times, airlines, and layovers]\\n\" +\n \"User preferences: morning departure, max 1 layover\"\n }\n ],\n modelPreferences: {\n hints: [{\n name: \"claude-3-5-sonnet\" // Suggested model\n }],\n costPriority: 0.3, // Less concerned about API cost\n speedPriority: 0.2, // Can wait for thorough analysis\n intelligencePriority: 0.9 // Need complex trade-off evaluation\n },\n systemPrompt: \"You are a travel expert helping users find the best flights based on their preferences\",\n maxTokens: 1500\n}\nExample: Flight Analysis Tool\nConsider a travel booking server with a tool called findBestFlight that uses sampling to analyze available flights and recommend the optimal choice. When a user asks \"Book me the best flight to Barcelona next month,\" the tool needs AI assistance to evaluate complex trade-offs.\nThe tool queries airline APIs and gathers 47 flight options. It then requests AI assistance to analyze these options: \"Analyze these flight options and recommend the best choice: [47 flights with prices, times, airlines, and layovers] User preferences: morning departure, max 1 layover.\"\nThe client initiates the sampling request, allowing the AI to evaluate trade-offs—like cheaper red-eye flights versus convenient morning departures. The tool uses this analysis to present the top three recommendations.\nUser Interaction Model\nWhile not a requirement, sampling is designed to allow human-in-the-loop control. Users can maintain oversight through several mechanisms:\nApproval controls: Sampling requests may require explicit user consent. Clients can show what the server wants to analyze and why. Users can approve, deny, or modify requests.\nTransparency features: Clients can display the exact prompt, model selection, and token limits, allowing users to review AI responses before they return to the server.\nConfiguration options: Users can set model preferences, configure auto-approval for trusted operations, or require approval for everything. Clients may provide options to redact sensitive information.\nSecurity considerations: Both clients and servers must handle sensitive data appropriately during sampling. Clients should implement rate limiting and validate all message content. The human-in-the-loop design ensures that server-initiated AI interactions cannot compromise security or access sensitive data without explicit user consent.",
      "updated_at": "1760788520.8599238",
      "filename": "client-concepts.md",
      "file_path": "client-concepts.md"
    },
    {
      "id": "md_connect-local-servers_a1bf61de",
      "url": "file://C:\\crawl\\connect-local-servers.md",
      "title": "Connect to local MCP servers",
      "content": "Connect to local MCP servers\n\nLearn how to extend Claude Desktop with local MCP servers to enable file system access and other powerful integrations\n\nModel Context Protocol (MCP) servers extend AI applications' capabilities by providing secure, controlled access to local resources and tools. Many clients support MCP, enabling diverse integration possibilities across different platforms and applications.\nThis guide demonstrates how to connect to local MCP servers using Claude Desktop as an example, one of the many clients that support MCP. While we focus on Claude Desktop's implementation, the concepts apply broadly to other MCP-compatible clients. By the end of this tutorial, Claude will be able to interact with files on your computer, create new documents, organize folders, and search through your file system—all with your explicit permission for each action.\n\nPrerequisites\nBefore starting this tutorial, ensure you have the following installed on your system:\nClaude Desktop\nDownload and install Claude Desktop for your operating system. Claude Desktop is available for macOS and Windows.\nIf you already have Claude Desktop installed, verify you're running the latest version by clicking the Claude menu and selecting \"Check for Updates...\"\nNode.js\nThe Filesystem Server and many other MCP servers require Node.js to run. Verify your Node.js installation by opening a terminal or command prompt and running:\nbash theme={null}\nnode --version\nIf Node.js is not installed, download it from nodejs.org. We recommend the LTS (Long Term Support) version for stability.\nUnderstanding MCP Servers\nMCP servers are programs that run on your computer and provide specific capabilities to Claude Desktop through a standardized protocol. Each server exposes tools that Claude can use to perform actions, with your approval. The Filesystem Server we'll install provides tools for:\n\nReading file contents and directory structures\nCreating new files and directories\nMoving and renaming files\nSearching for files by name or content\n\nAll actions require your explicit approval before execution, ensuring you maintain full control over what Claude can access and modify.\nInstalling the Filesystem Server\nThe process involves configuring Claude Desktop to automatically start the Filesystem Server whenever you launch the application. This configuration is done through a JSON file that tells Claude Desktop which servers to run and how to connect to them.\n\n Start by accessing the Claude Desktop settings. Click on the Claude menu in your system's menu bar (not the settings within the Claude window itself) and select \"Settings...\"\nOn macOS, this appears in the top menu bar:\n\n<Frame style={{ textAlign: \"center\" }}>\n <img src=\"https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-menu.png?fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=0c8b57e0e17af3624b6762a3ea944c8e\" width=\"400\" alt=\"Claude Desktop menu showing Settings option\" data-og-width=\"644\" data-og-height=\"568\" data-path=\"images/quickstart-menu.png\" data-optimize=\"true\" data-opv=\"3\" srcset=\"https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-menu.png?w=280&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=f997b6f31398840d3a824fa0eb9fec43 280w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-menu.png?w=560&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=062b0b3c342e4e02a8f2d690a48bcb24 560w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-menu.png?w=840&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=ae9b08052b7ea30b31d27432d8edf19e 840w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-menu.png?w=1100&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=7962cc4fb841fa0a04a3c6de03cf4d3d 1100w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-menu.png?w=1650&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=86bd79431e35b133d0ae4f74265f3d60 1650w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-menu.png?w=2500&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=1b300ae527efb4744aa08d5df94299a0 2500w\" />\n</Frame>\n\nThis opens the Claude Desktop configuration window, which is separate from your Claude account settings.\n\n In the Settings window, navigate to the \"Developer\" tab in the left sidebar. This section contains options for configuring MCP servers and other developer features.\nClick the \"Edit Config\" button to open the configuration file:\n\n<Frame>\n <img src=\"https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-developer.png?fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=0fb595490a2f9e15c0301e771a57446c\" alt=\"Developer settings showing Edit Config button\" data-og-width=\"1688\" width=\"1688\" data-og-height=\"534\" height=\"534\" data-path=\"images/quickstart-developer.png\" data-optimize=\"true\" data-opv=\"3\" srcset=\"https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-developer.png?w=280&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=0a7e615ee50a27a4e514668f7cbd9f57 280w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-developer.png?w=560&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=16d6d4721219afd7e2bfa41f0795e7e0 560w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-developer.png?w=840&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=612b1de5516ed7321d5b6939b5b3c823 840w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-developer.png?w=1100&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=840a428450dc0ec97538eb4e05050bcd 1100w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-developer.png?w=1650&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=59ae3a95918ff7f7b15e777c2d606496 1650w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-developer.png?w=2500&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=7838d7f023a281053786870336914f03 2500w\" />\n</Frame>\n\nThis action creates a new configuration file if one doesn't exist, or opens your existing configuration. The file is located at:\n\n* **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`\n* **Windows**: `%APPDATA%\\Claude\\claude_desktop_config.json`\n\n Replace the contents of the configuration file with the following JSON structure. This configuration tells Claude Desktop to start the Filesystem Server with access to specific directories:\n<CodeGroup>\n ```json macOS theme={null}\n {\n \"mcpServers\": {\n \"filesystem\": {\n \"command\": \"npx\",\n \"args\": [\n \"-y\",\n \"@modelcontextprotocol/server-filesystem\",\n \"/Users/username/Desktop\",\n \"/Users/username/Downloads\"\n ]\n }\n }\n }\n ```\n\n ```json Windows theme={null}\n {\n \"mcpServers\": {\n \"filesystem\": {\n \"command\": \"npx\",\n \"args\": [\n \"-y\",\n \"@modelcontextprotocol/server-filesystem\",\n \"C:\\\\Users\\\\username\\\\Desktop\",\n \"C:\\\\Users\\\\username\\\\Downloads\"\n ]\n }\n }\n }\n ```\n</CodeGroup>\n\nReplace `username` with your actual computer username. The paths listed in the `args` array specify which directories the Filesystem Server can access. You can modify these paths or add additional directories as needed.\n\n<Tip>\n **Understanding the Configuration**\n\n * `\"filesystem\"`: A friendly name for the server that appears in Claude Desktop\n * `\"command\": \"npx\"`: Uses Node.js's npx tool to run the server\n * `\"-y\"`: Automatically confirms the installation of the server package\n * `\"@modelcontextprotocol/server-filesystem\"`: The package name of the Filesystem Server\n * The remaining arguments: Directories the server is allowed to access\n</Tip>\n\n<Warning>\n **Security Consideration**\n\n Only grant access to directories you're comfortable with Claude reading and modifying. The server runs with your user account permissions, so it can perform any file operations you can perform manually.\n</Warning>\n\n After saving the configuration file, completely quit Claude Desktop and restart it. The application needs to restart to load the new configuration and start the MCP server.\nUpon successful restart, you'll see an MCP server indicator <img src=\"https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/claude-desktop-mcp-slider.svg?fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=2742ec3fb97067e8591e68546c90221e\" style={{display: 'inline', margin: 0, height: '1.3em'}} data-og-width=\"24\" width=\"24\" data-og-height=\"24\" height=\"24\" data-path=\"images/claude-desktop-mcp-slider.svg\" data-optimize=\"true\" data-opv=\"3\" srcset=\"https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/claude-desktop-mcp-slider.svg?w=280&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=52839f8519f476623c4fb5bb87ee24bd 280w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/claude-desktop-mcp-slider.svg?w=560&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=f0491976e108286441fc6554309c5c4f 560w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/claude-desktop-mcp-slider.svg?w=840&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=08e83eb102eda755a7db1eb27d16ebff 840w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/claude-desktop-mcp-slider.svg?w=1100&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=2524a80752928b0206e68e8e1890d1aa 1100w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/claude-desktop-mcp-slider.svg?w=1650&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=3c0dc88dadad5ed8e8af316965d00e0b 1650w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/claude-desktop-mcp-slider.svg?w=2500&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=702363a955a631c40c342f9557d5cfdd 2500w\" /> in the bottom-right corner of the conversation input box:\n\n<Frame>\n <img src=\"https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-slider.png?fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=f80a38b720fc0519079bae26e2aae312\" alt=\"Claude Desktop interface showing MCP server indicator\" data-og-width=\"1414\" width=\"1414\" data-og-height=\"410\" height=\"410\" data-path=\"images/quickstart-slider.png\" data-optimize=\"true\" data-opv=\"3\" srcset=\"https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-slider.png?w=280&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=24a0dc6f30664e953cc185ed0c7abc64 280w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-slider.png?w=560&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=d670a5fd82405775d7bc1e5f20a9a847 560w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-slider.png?w=840&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=5f66fa4bcaaf50ca905415f15af2e276 840w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-slider.png?w=1100&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=4aecd3c4b45c3aaac75a118d2d6edda5 1100w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-slider.png?w=1650&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=c7d321e2d25aa34552057a8866782549 1650w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-slider.png?w=2500&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=25dc1761b40b11ccb727b36183efa57f 2500w\" />\n</Frame>\n\nClick on this indicator to view the available tools provided by the Filesystem Server:\n\n<Frame style={{ textAlign: \"center\" }}>\n <img src=\"https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-tools.png?fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=18f045f27f31f40896d3710ce9a4a0a0\" width=\"400\" alt=\"Available filesystem tools in Claude Desktop\" data-og-width=\"978\" data-og-height=\"902\" data-path=\"images/quickstart-tools.png\" data-optimize=\"true\" data-opv=\"3\" srcset=\"https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-tools.png?w=280&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=298fc5cf79822ee781d15cf6374d8542 280w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-tools.png?w=560&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=c1e39ca66d9191dbe493cdcb52ad3fcb 560w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-tools.png?w=840&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=d797f46eb55126de14328ede4b735967 840w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-tools.png?w=1100&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=fcb9d89b6cef95bf9a3ffcd9231a4026 1100w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-tools.png?w=1650&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=23097f8f8b52a255246aeb83f85f949d 1650w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-tools.png?w=2500&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=0007b81f22a6a9b9a117981091e0221f 2500w\" />\n</Frame>\n\nIf the server indicator doesn't appear, refer to the [Troubleshooting](#troubleshooting) section for debugging steps.\n\nUsing the Filesystem Server\nWith the Filesystem Server connected, Claude can now interact with your file system. Try these example requests to explore the capabilities:\nFile Management Examples\n\n\"Can you write a poem and save it to my desktop?\" - Claude will compose a poem and create a new text file on your desktop\n\"What work-related files are in my downloads folder?\" - Claude will scan your downloads and identify work-related documents\n\"Please organize all images on my desktop into a new folder called 'Images'\" - Claude will create a folder and move image files into it\n\nHow Approval Works\nBefore executing any file system operation, Claude will request your approval. This ensures you maintain control over all actions:\n\nReview each request carefully before approving. You can always deny a request if you're not comfortable with the proposed action.\nTroubleshooting\nIf you encounter issues setting up or using the Filesystem Server, these solutions address common problems:\n\n 1. Restart Claude Desktop completely\n 2. Check your claude_desktop_config.json file syntax\n 3. Make sure the file paths included in claude_desktop_config.json are valid and that they are absolute and not relative\n 4. Look at logs to see why the server is not connecting\n 5. In your command line, try manually running the server (replacing username as you did in claude_desktop_config.json) to see if you get any errors:\n<CodeGroup>\n ```bash macOS/Linux theme={null}\n npx -y @modelcontextprotocol/server-filesystem /Users/username/Desktop /Users/username/Downloads\n ```\n\n ```powershell Windows theme={null}\n npx -y @modelcontextprotocol/server-filesystem C:\\Users\\username\\Desktop C:\\Users\\username\\Downloads\n ```\n</CodeGroup>\n\n Claude.app logging related to MCP is written to log files in:\n* macOS: `~/Library/Logs/Claude`\n\n* Windows: `%APPDATA%\\Claude\\logs`\n\n* `mcp.log` will contain general logging about MCP connections and connection failures.\n\n* Files named `mcp-server-SERVERNAME.log` will contain error (stderr) logging from the named server.\n\nYou can run the following command to list recent logs and follow along with any new ones (on Windows, it will only show recent logs):\n\n<CodeGroup>\n ```bash macOS/Linux theme={null}\n tail -n 20 -f ~/Library/Logs/Claude/mcp*.log\n ```\n\n ```powershell Windows theme={null}\n type \"%APPDATA%\\Claude\\logs\\mcp*.log\"\n ```\n</CodeGroup>\n\n If Claude attempts to use the tools but they fail:\n1. Check Claude's logs for errors\n2. Verify your server builds and runs without errors\n3. Try restarting Claude Desktop\n\n Please refer to our debugging guide for better debugging tools and more detailed guidance.\n \n\n If your configured server fails to load, and you see within its logs an error referring to ${APPDATA} within a path, you may need to add the expanded value of %APPDATA% to your env key in claude_desktop_config.json:\n```json theme={null}\n{\n \"brave-search\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@modelcontextprotocol/server-brave-search\"],\n \"env\": {\n \"APPDATA\": \"C:\\\\Users\\\\user\\\\AppData\\\\Roaming\\\\\",\n \"BRAVE_API_KEY\": \"...\"\n }\n }\n}\n```\n\nWith this change in place, launch Claude Desktop once again.\n\n<Warning>\n **NPM should be installed globally**\n\n The `npx` command may continue to fail if you have not installed NPM globally. If NPM is already installed globally, you will find `%APPDATA%\\npm` exists on your system. If not, you can install NPM globally by running the following command:\n\n ```bash theme={null}\n npm install -g npm\n ```\n</Warning>\n\nNext Steps\nNow that you've successfully connected Claude Desktop to a local MCP server, explore these options to expand your setup:\n\n Browse our collection of official and community-created MCP servers for\n additional capabilities\n \n\n Create custom MCP servers tailored to your specific workflows and\n integrations\n \n\n Learn how to connect Claude to remote MCP servers for cloud-based tools and\n services\n \n\n Dive deeper into how MCP works and its architecture",
      "updated_at": "1760788520.8599238",
      "filename": "connect-local-servers.md",
      "file_path": "connect-local-servers.md"
    },
    {
      "id": "md_connect-remote-servers_30c418e6",
      "url": "file://C:\\crawl\\connect-remote-servers.md",
      "title": "Connect to remote MCP Servers",
      "content": "Connect to remote MCP Servers\n\nLearn how to connect Claude to remote MCP servers and extend its capabilities with internet-hosted tools and data sources\n\nRemote MCP servers extend AI applications' capabilities beyond your local environment, providing access to internet-hosted tools, services, and data sources. By connecting to remote MCP servers, you transform AI assistants from helpful tools into informed teammates capable of handling complex, multi-step projects with real-time access to external resources.\nMany clients now support remote MCP servers, enabling a wide range of integration possibilities. This guide demonstrates how to connect to remote MCP servers using Claude as an example, one of the many clients that support MCP. While we focus on Claude's implementation through Custom Connectors, the concepts apply broadly to other MCP-compatible clients.\nUnderstanding Remote MCP Servers\nRemote MCP servers function similarly to local MCP servers but are hosted on the internet rather than your local machine. They expose tools, prompts, and resources that Claude can use to perform tasks on your behalf. These servers can integrate with various services such as project management tools, documentation systems, code repositories, and any other API-enabled service.\nThe key advantage of remote MCP servers is their accessibility. Unlike local servers that require installation and configuration on each device, remote servers are available from any MCP client with an internet connection. This makes them ideal for web-based AI applications, integrations that emphasize ease-of-use and services that require server-side processing or authentication.\nWhat are Custom Connectors?\nCustom Connectors serve as the bridge between Claude and remote MCP servers. They allow you to connect Claude directly to the tools and data sources that matter most to your workflows, enabling Claude to operate within your favorite software and draw insights from the complete context of your external tools.\nWith Custom Connectors, you can:\n\nConnect Claude to existing remote MCP servers provided by third-party developers\nBuild your own remote MCP servers to connect with any tool\n\nConnecting to a Remote MCP Server\nThe process of connecting Claude to a remote MCP server involves adding a Custom Connector through the Claude interface. This establishes a secure connection between Claude and your chosen remote server.\n\n Open Claude in your browser and navigate to the settings page. You can access this by clicking on your profile icon and selecting \"Settings\" from the dropdown menu. Once in settings, locate and click on the \"Connectors\" section in the sidebar.\nThis will display your currently configured connectors and provide options to add new ones.\n\n In the Connectors section, scroll to the bottom where you'll find the \"Add custom connector\" button. Click this button to begin the connection process.\n<Frame>\n <img src=\"https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/1-add-connector.png?fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=b5ae9b23164875bbaa3aff4c178cdc64\" alt=\"Add custom connector button in Claude settings\" data-og-width=\"1038\" width=\"1038\" data-og-height=\"809\" height=\"809\" data-path=\"images/quickstart-remote/1-add-connector.png\" data-optimize=\"true\" data-opv=\"3\" srcset=\"https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/1-add-connector.png?w=280&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=df494c13492290da8cbf33320405bc60 280w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/1-add-connector.png?w=560&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=a2dce224fb5e1636218ea2806962c89f 560w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/1-add-connector.png?w=840&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=de18294dd3cad23989c04cedbacff74f 840w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/1-add-connector.png?w=1100&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=c55cb3531701df2b5dfd721dcd3f48dc 1100w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/1-add-connector.png?w=1650&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=b0d3e56c4c445ba6896d49997dcdf2c0 1650w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/1-add-connector.png?w=2500&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=9d83f4f2db7441a39ff8733d97243ab9 2500w\" />\n</Frame>\n\nA dialog will appear prompting you to enter the remote MCP server URL. This URL should be provided by the server developer or administrator. Enter the complete URL, ensuring it includes the proper protocol (https\\://) and any necessary path components.\n\n<Frame>\n <img src=\"https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/2-connect.png?fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=0934f16d8e016cade8e560c8f89d011b\" alt=\"Dialog for entering remote MCP server URL\" data-og-width=\"1616\" width=\"1616\" data-og-height=\"282\" height=\"282\" data-path=\"images/quickstart-remote/2-connect.png\" data-optimize=\"true\" data-opv=\"3\" srcset=\"https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/2-connect.png?w=280&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=e3d7318b0b8e691d25e1887e80200b60 280w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/2-connect.png?w=560&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=be3edc7b361eecaabf688c2058b5e466 560w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/2-connect.png?w=840&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=31be86114b31e1c5e813d92a4c0cb1c3 840w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/2-connect.png?w=1100&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=15b6cd3819fabd3655a52b930d384b51 1100w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/2-connect.png?w=1650&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=5ef180101a7fb0901f7ecf1b5efd254f 1650w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/2-connect.png?w=2500&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=c024f625ec6ee3f7959513ba15adf524 2500w\" />\n</Frame>\n\nAfter entering the URL, click \"Add\" to proceed with the connection.\n\n Most remote MCP servers require authentication to ensure secure access to their resources. The authentication process varies depending on the server implementation but commonly involves OAuth, API keys, or username/password combinations.\n<Frame>\n <img src=\"https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/3-auth.png?fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=89af6e1b85718637231388697cc7b015\" alt=\"Authentication screen for remote MCP server\" data-og-width=\"490\" width=\"490\" data-og-height=\"806\" height=\"806\" data-path=\"images/quickstart-remote/3-auth.png\" data-optimize=\"true\" data-opv=\"3\" srcset=\"https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/3-auth.png?w=280&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=cde1e30b4c3b99b5edc5575c5958e9e7 280w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/3-auth.png?w=560&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=e2cef2daadce577ce335949d3f425257 560w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/3-auth.png?w=840&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=4e06599391ebf6bcb521cb4000469844 840w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/3-auth.png?w=1100&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=e78e71303fd5bb7d1e5c1602dca7641b 1100w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/3-auth.png?w=1650&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=2e49d390bddf2a37fef4cba409e9950f 1650w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/3-auth.png?w=2500&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=47ec70901a76a3209267b2078f9f8011 2500w\" />\n</Frame>\n\nFollow the authentication prompts provided by the server. This may redirect you to a third-party authentication provider or display a form within Claude. Once authentication is complete, Claude will establish a secure connection to the remote server.\n\n After successful connection, the remote server's resources and prompts become available in your Claude conversations. You can access these by clicking the paperclip icon in the message input area, which opens the attachment menu.\n<Frame>\n <img src=\"https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/4-select-resources-menu.png?fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=ecc6234b0fe5625e24cc2b02b7893c67\" alt=\"Attachment menu showing available resources\" data-og-width=\"735\" width=\"735\" data-og-height=\"666\" height=\"666\" data-path=\"images/quickstart-remote/4-select-resources-menu.png\" data-optimize=\"true\" data-opv=\"3\" srcset=\"https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/4-select-resources-menu.png?w=280&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=6e853446286f2c2caf1c7137e4293db4 280w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/4-select-resources-menu.png?w=560&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=7c3c5b7d2f8d078bc263b0603a4136d1 560w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/4-select-resources-menu.png?w=840&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=280e1d1547925f73f33fcf404eac5ba2 840w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/4-select-resources-menu.png?w=1100&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=00fc5842c2d6592f41f96c2051b016e2 1100w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/4-select-resources-menu.png?w=1650&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=505d4ec95d83f4e52cf9c60780b225fe 1650w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/4-select-resources-menu.png?w=2500&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=07178c22a89472b962639854dc029953 2500w\" />\n</Frame>\n\nThe menu displays all available resources and prompts from your connected servers. Select the items you want to include in your conversation. These resources provide Claude with context and information from your external tools.\n\n<Frame>\n <img src=\"https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/5-select-prompts-resources.png?fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=30c522540c7ff5abd8617d20b329eca2\" alt=\"Selecting specific resources and prompts from the menu\" data-og-width=\"648\" width=\"648\" data-og-height=\"920\" height=\"920\" data-path=\"images/quickstart-remote/5-select-prompts-resources.png\" data-optimize=\"true\" data-opv=\"3\" srcset=\"https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/5-select-prompts-resources.png?w=280&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=7361585026d3dd1f0c218232ce475d59 280w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/5-select-prompts-resources.png?w=560&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=eb5162947ac8110569225e4ff36ac54c 560w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/5-select-prompts-resources.png?w=840&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=93b0b1de76b11785deb6cd2b8bbbb33e 840w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/5-select-prompts-resources.png?w=1100&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=19d1f1de9b7b38dff6fabaea260fc700 1100w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/5-select-prompts-resources.png?w=1650&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=587ee6b0f0831f7b9c827db58e4c53a6 1650w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/5-select-prompts-resources.png?w=2500&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=a875a3599b478977e1322c07b82a5879 2500w\" />\n</Frame>\n\n Remote MCP servers often expose multiple tools with varying capabilities. You can control which tools Claude is allowed to use by configuring permissions in the connector settings. This ensures Claude only performs actions you've explicitly authorized.\n<Frame>\n <img src=\"https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/6-configure-tools.png?fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=1e55fd2f7da85150bfcf9dfbd7a31f44\" alt=\"Tool permission configuration interface\" data-og-width=\"604\" width=\"604\" data-og-height=\"745\" height=\"745\" data-path=\"images/quickstart-remote/6-configure-tools.png\" data-optimize=\"true\" data-opv=\"3\" srcset=\"https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/6-configure-tools.png?w=280&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=6ece557353a2b8227cfc033ee7533fbc 280w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/6-configure-tools.png?w=560&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=aa954f4a018077d6a4a3c9406cdd4a63 560w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/6-configure-tools.png?w=840&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=309fd1583dd23081ed93eca4fb85c5e0 840w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/6-configure-tools.png?w=1100&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=8b7ea5b326ea5cf8947e9b9aba28f2f7 1100w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/6-configure-tools.png?w=1650&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=7e02024cdcae2b7c41aab3d5c4f4e75e 1650w, https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/quickstart-remote/6-configure-tools.png?w=2500&fit=max&auto=format&n=4ZXF1PrDkEaJvXpn&q=85&s=f953404ab1cb149e160eaa139c53d701 2500w\" />\n</Frame>\n\nNavigate back to the Connectors settings and click on your connected server. Here you can enable or disable specific tools, set usage limits, and configure other security parameters according to your needs.\n\nBest Practices for Using Remote MCP Servers\nWhen working with remote MCP servers, consider these recommendations to ensure a secure and efficient experience:\nSecurity considerations: Always verify the authenticity of remote MCP servers before connecting. Only connect to servers from trusted sources, and review the permissions requested during authentication. Be cautious about granting access to sensitive data or systems.\nManaging multiple connectors: You can connect to multiple remote MCP servers simultaneously. Organize your connectors by purpose or project to maintain clarity. Regularly review and remove connectors you no longer use to keep your workspace organized and secure.\nNext Steps\nNow that you've connected Claude to a remote MCP server, you can explore its capabilities in your conversations. Try using the connected tools to automate tasks, access external data, or integrate with your existing workflows.\n\n Create custom remote MCP servers to integrate with proprietary tools and\n services\n \n\n Browse our collection of official and community-created MCP servers\n \n\n Learn how to connect Claude Desktop to local MCP servers for direct system\n access\n \n\n Dive deeper into how MCP works and its architecture\n \n\nRemote MCP servers unlock powerful possibilities for extending Claude's capabilities. As you become familiar with these integrations, you'll discover new ways to streamline your workflows and accomplish complex tasks more efficiently.",
      "updated_at": "1760788520.8599238",
      "filename": "connect-remote-servers.md",
      "file_path": "connect-remote-servers.md"
    },
    {
      "id": "md_inspector_e7fdfbe6",
      "url": "file://C:\\crawl\\inspector.md",
      "title": "MCP Inspector",
      "content": "MCP Inspector\n\nIn-depth guide to using the MCP Inspector for testing and debugging Model Context Protocol servers\n\nThe MCP Inspector is an interactive developer tool for testing and debugging MCP servers. While the Debugging Guide covers the Inspector as part of the overall debugging toolkit, this document provides a detailed exploration of the Inspector's features and capabilities.\nGetting started\nInstallation and basic usage\nThe Inspector runs directly through npx without requiring installation:\nbash theme={null}\nnpx @modelcontextprotocol/inspector <command>\nbash theme={null}\nnpx @modelcontextprotocol/inspector <command> <arg1> <arg2>\nInspecting servers from NPM or PyPi\nA common way to start server packages from NPM or PyPi.\n\nbash theme={null}\n npx -y @modelcontextprotocol/inspector npx <package-name> <args>\n # For example\n npx -y @modelcontextprotocol/inspector npx @modelcontextprotocol/server-filesystem /Users/username/Desktop\n\nbash theme={null}\n npx @modelcontextprotocol/inspector uvx <package-name> <args>\n # For example\n npx @modelcontextprotocol/inspector uvx mcp-server-git --repository ~/code/mcp/servers.git\n\nInspecting locally developed servers\nTo inspect servers locally developed or downloaded as a repository, the most common\nway is:\n\nbash theme={null}\n npx @modelcontextprotocol/inspector node path/to/server/index.js args...\n\nbash theme={null}\n npx @modelcontextprotocol/inspector \\\n uv \\\n --directory path/to/server \\\n run \\\n package-name \\\n args...\n\nPlease carefully read any attached README for the most accurate instructions.\nFeature overview\n\nThe Inspector provides several features for interacting with your MCP server:\nServer connection pane\n\nAllows selecting the transport for connecting to the server\nFor local servers, supports customizing the command-line arguments and environment\n\nResources tab\n\nLists all available resources\nShows resource metadata (MIME types, descriptions)\nAllows resource content inspection\nSupports subscription testing\n\nPrompts tab\n\nDisplays available prompt templates\nShows prompt arguments and descriptions\nEnables prompt testing with custom arguments\nPreviews generated messages\n\nTools tab\n\nLists available tools\nShows tool schemas and descriptions\nEnables tool testing with custom inputs\nDisplays tool execution results\n\nNotifications pane\n\nPresents all logs recorded from the server\nShows notifications received from the server\n\nBest practices\nDevelopment workflow\n\nStart Development\nLaunch Inspector with your server\nVerify basic connectivity\n\nCheck capability negotiation\n\nIterative testing\n\nMake server changes\nRebuild the server\nReconnect the Inspector\nTest affected features\n\nMonitor messages\n\nTest edge cases\n\nInvalid inputs\nMissing prompt arguments\nConcurrent operations\nVerify error handling and error responses\n\nNext steps\n\n Check out the MCP Inspector source code\n \n\n Learn about broader debugging strategies",
      "updated_at": "1760788520.8554032",
      "filename": "inspector.md",
      "file_path": "inspector.md"
    },
    {
      "id": "md_intro_96f49227",
      "url": "file://C:\\crawl\\intro.md",
      "title": "What is the Model Context Protocol (MCP)?",
      "content": "What is the Model Context Protocol (MCP)?\nMCP (Model Context Protocol) is an open-source standard for connecting AI applications to external systems.\nUsing MCP, AI applications like Claude or ChatGPT can connect to data sources (e.g. local files, databases), tools (e.g. search engines, calculators) and workflows (e.g. specialized prompts)—enabling them to access key information and perform tasks.\nThink of MCP like a USB-C port for AI applications. Just as USB-C provides a standardized way to connect electronic devices, MCP provides a standardized way to connect AI applications to external systems.\n\nWhat can MCP enable?\n\nAgents can access your Google Calendar and Notion, acting as a more personalized AI assistant.\nClaude Code can generate an entire web app using a Figma design.\nEnterprise chatbots can connect to multiple databases across an organization, empowering users to analyze data using chat.\nAI models can create 3D designs on Blender and print them out using a 3D printer.\n\nWhy does MCP matter?\nDepending on where you sit in the ecosystem, MCP can have a range of benefits.\n\nDevelopers: MCP reduces development time and complexity when building, or integrating with, an AI application or agent.\nAI applications or agents: MCP provides access to an ecosystem of data sources, tools and apps which will enhance capabilities and improve the end-user experience.\nEnd-users: MCP results in more capable AI applications or agents which can access your data and take actions on your behalf when necessary.\n\nStart Building\n\n Create MCP servers to expose your data and tools\n \n\n Develop applications that connect to MCP servers\n \n\nLearn more\n\n Learn the core concepts and architecture of MCP",
      "updated_at": "1760788413.1773403",
      "filename": "intro.md",
      "file_path": "intro.md"
    },
    {
      "id": "md_sdk_d1ddea8c",
      "url": "file://C:\\crawl\\sdk.md",
      "title": "SDKs",
      "content": "SDKs\n\nOfficial SDKs for building with Model Context Protocol\n\nBuild MCP servers and clients using our official SDKs. All SDKs provide the same core functionality and full protocol support.\nAvailable SDKs\n\nGetting Started\nEach SDK provides the same functionality but follows the idioms and best practices of its language. All SDKs support:\n\nCreating MCP servers that expose tools, resources, and prompts\nBuilding MCP clients that can connect to any MCP server\nLocal and remote transport protocols\nProtocol compliance with type safety\n\nVisit the SDK page for your chosen language to find installation instructions, documentation, and examples.\nNext Steps\nReady to start building with MCP? Choose your path:\n\n Learn how to create your first MCP server\n \n\n Create applications that connect to MCP servers",
      "updated_at": "1760788520.8554032",
      "filename": "sdk.md",
      "file_path": "sdk.md"
    },
    {
      "id": "md_server-concepts_b2e90da1",
      "url": "file://C:\\crawl\\server-concepts.md",
      "title": "Understanding MCP servers",
      "content": "Understanding MCP servers\nMCP servers are programs that expose specific capabilities to AI applications through standardized protocol interfaces.\nCommon examples include file system servers for document access, database servers for data queries, GitHub servers for code management, Slack servers for team communication, and calendar servers for scheduling.\nCore Server Features\nServers provide functionality through three building blocks:\n| Feature | Explanation | Examples | Who controls it |\n| ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ | --------------- |\n| Tools | Functions that your LLM can actively call, and decides when to use them based on user requests. Tools can write to databases, call external APIs, modify files, or trigger other logic. | Search flightsSend messagesCreate calendar events | Model |\n| Resources | Passive data sources that provide read-only access to information for context, such as file contents, database schemas, or API documentation. | Retrieve documentsAccess knowledge basesRead calendars | Application |\n| Prompts | Pre-built instruction templates that tell the model to work with specific tools and resources. | Plan a vacationSummarize my meetingsDraft an email | User |\nWe will use a hypothetical scenario to demonstrate the role of each of these features, and show how they can work together.\nTools\nTools enable AI models to perform actions. Each tool defines a specific operation with typed inputs and outputs. The model requests tool execution based on context.\nHow Tools Work\nTools are schema-defined interfaces that LLMs can invoke. MCP uses JSON Schema for validation. Each tool performs a single operation with clearly defined inputs and outputs. Tools may require user consent prior to execution, helping to ensure users maintain control over actions taken by a model.\nProtocol operations:\n| Method | Purpose | Returns |\n| ------------ | ------------------------ | -------------------------------------- |\n| tools/list | Discover available tools | Array of tool definitions with schemas |\n| tools/call | Execute a specific tool | Tool execution result |\nExample tool definition:\ntypescript theme={null}\n{\n name: \"searchFlights\",\n description: \"Search for available flights\",\n inputSchema: {\n type: \"object\",\n properties: {\n origin: { type: \"string\", description: \"Departure city\" },\n destination: { type: \"string\", description: \"Arrival city\" },\n date: { type: \"string\", format: \"date\", description: \"Travel date\" }\n },\n required: [\"origin\", \"destination\", \"date\"]\n }\n}\nExample: Travel Booking\nTools enable AI applications to perform actions on behalf of users. In a travel planning scenario, the AI application might use several tools to help book a vacation:\nFlight Search\nsearchFlights(origin: \"NYC\", destination: \"Barcelona\", date: \"2024-06-15\")\nQueries multiple airlines and returns structured flight options.\nCalendar Blocking\ncreateCalendarEvent(title: \"Barcelona Trip\", startDate: \"2024-06-15\", endDate: \"2024-06-22\")\nMarks the travel dates in the user's calendar.\nEmail notification\nsendEmail(to: \"team@work.com\", subject: \"Out of Office\", body: \"...\")\nSends an automated out-of-office message to colleagues.\nUser Interaction Model\nTools are model-controlled, meaning AI models can discover and invoke them automatically. However, MCP emphasizes human oversight through several mechanisms.\nFor trust and safety, applications can implement user control through various mechanisms, such as:\n\nDisplaying available tools in the UI, enabling users to define whether a tool should be made available in specific interactions\nApproval dialogs for individual tool executions\nPermission settings for pre-approving certain safe operations\nActivity logs that show all tool executions with their results\n\nResources\nResources provide structured access to information that the AI application can retrieve and provide to models as context.\nHow Resources Work\nResources expose data from files, APIs, databases, or any other source that an AI needs to understand context. Applications can access this information directly and decide how to use it - whether that's selecting relevant portions, searching with embeddings, or passing it all to the model.\nEach resource has a unique URI (like file:///path/to/document.md) and declares its MIME type for appropriate content handling. They declare MIME types for appropriate content handling and support two discovery patterns:\n\nDirect Resources - fixed URIs that point to specific data. Example: calendar://events/2024 - returns calendar availability for 2024\nResource Templates - dynamic URIs with parameters for flexible queries. Example:\ntravel://activities/{city}/{category} - returns activities by city and category\ntravel://activities/barcelona/museums - returns all museums in Barcelona\n\nResource Templates include metadata such as title, description, and expected MIME type, making them discoverable and self-documenting.\nProtocol operations:\n| Method | Purpose | Returns |\n| -------------------------- | ------------------------------- | -------------------------------------- |\n| resources/list | List available direct resources | Array of resource descriptors |\n| resources/templates/list | Discover resource templates | Array of resource template definitions |\n| resources/read | Retrieve resource contents | Resource data with metadata |\n| resources/subscribe | Monitor resource changes | Subscription confirmation |\nExample: Getting Travel Planning Context\nContinuing with the travel planning example, resources provide the AI application with access to relevant information:\n\nCalendar data (calendar://events/2024) - Checks user availability\nTravel documents (file:///Documents/Travel/passport.pdf) - Accesses important documents\nPrevious itineraries (trips://history/barcelona-2023) - References past trips and preferences\n\nThe AI application retrieves these resources and decides how to process them, whether selecting a subset of data using embeddings or keyword search, or passing raw data directly to the model.\nIn this case, it provides calendar data, weather information, and travel preferences to the model, enabling it to check availability, look up weather patterns, and reference past travel preferences.\nResource Template Examples:\n```json theme={null}\n{\n \"uriTemplate\": \"weather://forecast/{city}/{date}\",\n \"name\": \"weather-forecast\",\n \"title\": \"Weather Forecast\",\n \"description\": \"Get weather forecast for any city and date\",\n \"mimeType\": \"application/json\"\n}\n{\n \"uriTemplate\": \"travel://flights/{origin}/{destination}\",\n \"name\": \"flight-search\",\n \"title\": \"Flight Search\",\n \"description\": \"Search available flights between cities\",\n \"mimeType\": \"application/json\"\n}\n```\nThese templates enable flexible queries. For weather data, users can access forecasts for any city/date combination. For flights, they can search routes between any two airports. When a user has input \"NYC\" as the origin airport and begins to input \"Bar\" as the destination airport, the system can suggest \"Barcelona (BCN)\" or \"Barbados (BGI)\".\nParameter Completion\nDynamic resources support parameter completion. For example:\n\nTyping \"Par\" as input for weather://forecast/{city} might suggest \"Paris\" or \"Park City\"\nTyping \"JFK\" for flights://search/{airport} might suggest \"JFK - John F. Kennedy International\"\n\nThe system helps discover valid values without requiring exact format knowledge.\nUser Interaction Model\nResources are application-driven, giving them flexibility in how they retrieve, process, and present available context. Common interaction patterns include:\n\nTree or list views for browsing resources in familiar folder-like structures\nSearch and filter interfaces for finding specific resources\nAutomatic context inclusion or smart suggestions based on heuristics or AI selection\nManual or bulk selection interfaces for including single or multiple resources\n\nApplications are free to implement resource discovery through any interface pattern that suits their needs. The protocol doesn't mandate specific UI patterns, allowing for resource pickers with preview capabilities, smart suggestions based on current conversation context, bulk selection for including multiple resources, or integration with existing file browsers and data explorers.\nPrompts\nPrompts provide reusable templates. They allow MCP server authors to provide parameterized prompts for a domain, or showcase how to best use the MCP server.\nHow Prompts Work\nPrompts are structured templates that define expected inputs and interaction patterns. They are user-controlled, requiring explicit invocation rather than automatic triggering. Prompts can be context-aware, referencing available resources and tools to create comprehensive workflows. Similar to resources, prompts support parameter completion to help users discover valid argument values.\nProtocol operations:\n| Method | Purpose | Returns |\n| -------------- | -------------------------- | ------------------------------------- |\n| prompts/list | Discover available prompts | Array of prompt descriptors |\n| prompts/get | Retrieve prompt details | Full prompt definition with arguments |\nExample: Streamlined Workflows\nPrompts provide structured templates for common tasks. In the travel planning context:\n\"Plan a vacation\" prompt:\njson theme={null}\n{\n \"name\": \"plan-vacation\",\n \"title\": \"Plan a vacation\",\n \"description\": \"Guide through vacation planning process\",\n \"arguments\": [\n { \"name\": \"destination\", \"type\": \"string\", \"required\": true },\n { \"name\": \"duration\", \"type\": \"number\", \"description\": \"days\" },\n { \"name\": \"budget\", \"type\": \"number\", \"required\": false },\n { \"name\": \"interests\", \"type\": \"array\", \"items\": { \"type\": \"string\" } }\n ]\n}\nRather than unstructured natural language input, the prompt system enables:\n\nSelection of the \"Plan a vacation\" template\nStructured input: Barcelona, 7 days, \\$3000, [\"beaches\", \"architecture\", \"food\"]\nConsistent workflow execution based on the template\n\nUser Interaction Model\nPrompts are user-controlled, requiring explicit invocation. The protocol gives implementers freedom to design interfaces that feel natural within their application. Key principles include:\n\nEasy discovery of available prompts\nClear descriptions of what each prompt does\nNatural argument input with validation\nTransparent display of the prompt's underlying template\n\nApplications typically expose prompts through various UI patterns such as:\n\nSlash commands (typing \"/\" to see available prompts like /plan-vacation)\nCommand palettes for searchable access\nDedicated UI buttons for frequently used prompts\nContext menus that suggest relevant prompts\n\nBringing Servers Together\nThe real power of MCP emerges when multiple servers work together, combining their specialized capabilities through a unified interface.\nExample: Multi-Server Travel Planning\nConsider a personalized AI travel planner application, with three connected servers:\n\nTravel Server - Handles flights, hotels, and itineraries\nWeather Server - Provides climate data and forecasts\nCalendar/Email Server - Manages schedules and communications\n\nThe Complete Flow\n\nUser invokes a prompt with parameters:\n\njson theme={null}\n {\n \"prompt\": \"plan-vacation\",\n \"arguments\": {\n \"destination\": \"Barcelona\",\n \"departure_date\": \"2024-06-15\",\n \"return_date\": \"2024-06-22\",\n \"budget\": 3000,\n \"travelers\": 2\n }\n }\n\nUser selects resources to include:\ncalendar://my-calendar/June-2024 (from Calendar Server)\ntravel://preferences/europe (from Travel Server)\n\ntravel://past-trips/Spain-2023 (from Travel Server)\n\nAI processes the request using tools:\n\nThe AI first reads all selected resources to gather context - identifying available dates from the calendar, learning preferred airlines and hotel types from travel preferences, and discovering previously enjoyed locations from past trips.\nUsing this context, the AI then executes a series of Tools:\n\nsearchFlights() - Queries airlines for NYC to Barcelona flights\ncheckWeather() - Retrieves climate forecasts for travel dates\n\nThe AI then uses this information to create the booking and following steps, requesting approval from the user where necessary:\n\nbookHotel() - Finds hotels within the specified budget\ncreateCalendarEvent() - Adds the trip to the user's calendar\nsendEmail() - Sends confirmation with trip details\n\nThe result: Through multiple MCP servers, the user researched and booked a Barcelona trip tailored to their schedule. The \"Plan a Vacation\" prompt guided the AI to combine Resources (calendar availability and travel history) with Tools (searching flights, booking hotels, updating calendars) across different servers—gathering context and executing the booking. A task that could've taken hours was completed in minutes using MCP.",
      "updated_at": "1760788520.8599238",
      "filename": "server-concepts.md",
      "file_path": "server-concepts.md"
    },
    {
      "id": "md_versioning_2b1431db",
      "url": "file://C:\\crawl\\versioning.md",
      "title": "Versioning",
      "content": "Versioning\nThe Model Context Protocol uses string-based version identifiers following the format\nYYYY-MM-DD, to indicate the last date backwards incompatible changes were made.\n\n The protocol version will not be incremented when the\n protocol is updated, as long as the changes maintain backwards compatibility. This allows\n for incremental improvements while preserving interoperability.\n\nRevisions\nRevisions may be marked as:\n\nDraft: in-progress specifications, not yet ready for consumption.\nCurrent: the current protocol version, which is ready for use and may continue to\n receive backwards compatible changes.\nFinal: past, complete specifications that will not be changed.\n\nThe current protocol version is 2025-06-18.\nNegotiation\nVersion negotiation happens during\ninitialization. Clients and\nservers MAY support multiple protocol versions simultaneously, but they MUST\nagree on a single version to use for the session.\nThe protocol provides appropriate error handling if version negotiation fails, allowing\nclients to gracefully terminate connections when they cannot find a version compatible\nwith the server.",
      "updated_at": "1760788520.8599238",
      "filename": "versioning.md",
      "file_path": "versioning.md"
    }
  ]
}