From 2d987afeedd2998a940e228ee29ee70cb53b0d37 Mon Sep 17 00:00:00 2001 From: Zack Lee Date: Sun, 17 Nov 2024 20:10:29 -0500 Subject: [PATCH 1/6] first commit --- .DS_Store | Bin 0 -> 6148 bytes .prettierignore | 1 + .../client-api/connection-management.mdx | 8 + .../client-api/resource-consumption.mdx | 8 + api-reference/client-api/tool-invocation.mdx | 8 + api-reference/endpoint/create.mdx | 4 - api-reference/endpoint/delete.mdx | 4 - api-reference/endpoint/get.mdx | 4 - api-reference/error-handling.mdx | 8 + api-reference/introduction.mdx | 33 -- api-reference/message-types.mdx | 8 + api-reference/openapi.json | 195 --------- api-reference/protocol-overview.mdx | 8 + api-reference/python/class-reference.mdx | 8 + api-reference/python/examples.mdx | 8 + api-reference/python/type-hints.mdx | 8 + api-reference/server-api/event-handling.mdx | 8 + .../server-api/resource-management.mdx | 8 + .../server-api/tool-implementation.mdx | 8 + api-reference/typescript/class-reference.mdx | 8 + api-reference/typescript/examples.mdx | 8 + api-reference/typescript/type-definitions.mdx | 8 + create-docs.sh | 75 ++++ development.mdx | 106 ----- docs/deployment/configuration.mdx | 5 + docs/deployment/environment-setup.mdx | 4 + docs/deployment/monitoring.mdx | 8 + docs/development.mdx | 0 docs/guides/first-mcp-server.mdx | 8 + docs/guides/implementing-tools.mdx | 8 + docs/guides/integrating-with-llm.mdx | 385 ++++++++++++++++++ docs/guides/security-best-practices.mdx | 8 + docs/guides/testing-debugging.mdx | 8 + docs/guides/working-with-resources.mdx | 8 + docs/installation.mdx | 160 ++++++++ docs/key-concepts.mdx | 12 + docs/recipes/api-integration.mdx | 8 + docs/recipes/database-integration.mdx | 8 + docs/recipes/local-files.mdx | 8 + docs/recipes/realtime-updates.mdx | 8 + essentials/code.mdx | 37 -- essentials/images.mdx | 59 --- essentials/markdown.mdx | 88 ---- essentials/navigation.mdx | 66 --- essentials/reusable-snippets.mdx | 110 ----- essentials/settings.mdx | 318 --------------- images/modelcontextprotocol.png | Bin 0 -> 22447 bytes introduction.mdx | 16 +- logo/dark.png | Bin 0 -> 1682 bytes logo/light.png | Bin 0 -> 1575 bytes mint.json | 91 +++-- quickstart.mdx | 351 +++++++++++++--- your-first-server.mdx | 319 +++++++++++++++ 53 files changed, 1516 insertions(+), 1127 deletions(-) create mode 100644 .DS_Store create mode 100644 .prettierignore create mode 100644 api-reference/client-api/connection-management.mdx create mode 100644 api-reference/client-api/resource-consumption.mdx create mode 100644 api-reference/client-api/tool-invocation.mdx delete mode 100644 api-reference/endpoint/create.mdx delete mode 100644 api-reference/endpoint/delete.mdx delete mode 100644 api-reference/endpoint/get.mdx create mode 100644 api-reference/error-handling.mdx delete mode 100644 api-reference/introduction.mdx create mode 100644 api-reference/message-types.mdx delete mode 100644 api-reference/openapi.json create mode 100644 api-reference/protocol-overview.mdx create mode 100644 api-reference/python/class-reference.mdx create mode 100644 api-reference/python/examples.mdx create mode 100644 api-reference/python/type-hints.mdx create mode 100644 api-reference/server-api/event-handling.mdx create mode 100644 api-reference/server-api/resource-management.mdx create mode 100644 api-reference/server-api/tool-implementation.mdx create mode 100644 api-reference/typescript/class-reference.mdx create mode 100644 api-reference/typescript/examples.mdx create mode 100644 api-reference/typescript/type-definitions.mdx create mode 100644 create-docs.sh delete mode 100644 development.mdx create mode 100644 docs/deployment/configuration.mdx create mode 100644 docs/deployment/environment-setup.mdx create mode 100644 docs/deployment/monitoring.mdx create mode 100644 docs/development.mdx create mode 100644 docs/guides/first-mcp-server.mdx create mode 100644 docs/guides/implementing-tools.mdx create mode 100644 docs/guides/integrating-with-llm.mdx create mode 100644 docs/guides/security-best-practices.mdx create mode 100644 docs/guides/testing-debugging.mdx create mode 100644 docs/guides/working-with-resources.mdx create mode 100644 docs/installation.mdx create mode 100644 docs/key-concepts.mdx create mode 100644 docs/recipes/api-integration.mdx create mode 100644 docs/recipes/database-integration.mdx create mode 100644 docs/recipes/local-files.mdx create mode 100644 docs/recipes/realtime-updates.mdx delete mode 100644 essentials/code.mdx delete mode 100644 essentials/images.mdx delete mode 100644 essentials/markdown.mdx delete mode 100644 essentials/navigation.mdx delete mode 100644 essentials/reusable-snippets.mdx delete mode 100644 essentials/settings.mdx create mode 100644 images/modelcontextprotocol.png create mode 100644 logo/dark.png create mode 100644 logo/light.png create mode 100644 your-first-server.mdx diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..a123578f911e8d1eab8bfaea4ddf9c04be790c6f GIT binary patch literal 6148 zcmeHKO>fgM7=GQAEu}DeVA76}xOSym0cqN$E8T$umleSQP-&J>!qT`T=?bbU^$h=k zzrdAW!hhie&ue>9(iS8x2r<8v{W#A1)b{iGBPJrznfUueH6n757|Yj@tucPjX~jyW z<_1ux|A4ioHO}uiuOsSjj%Ue-z0xFOnWSd7Jox z)cBzcC88?5rUBR?oniIIV5N8(7Fpuc5^EFwBk+c3HC^)k{ySf9nvP9xzIx**OtWV5 zn<#CRuWfEQTTaz^*?S|Wy=;(8(#{}x&QDLIjJ(V8zk#q zFP??5FQ*+jiTzY@d-{b_aVq`V?re7d@SyItTKn_5J3BmR*4=xp2lIKw*|~G~=(K+x zjbizcWxD1n|nO`vOr8m;Y`h?JO@k4Ra? zaY(YLD;>k{b1rffL_oLHptpz`T3BLmtn-X*dWZgSq|f1>A$|$+wev(pJkPDrDV?AX zU3v^uoMLN&sMhiSu5u^Q)@XC9fK{NVz=nRT z@%ex9>-&F^WS^`8R)POY0a5Pux*ZJ3oUJQ^d;K75J+P`~)Ye-HreN literal 0 HcmV?d00001 diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..b17149b --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +*.mdx \ No newline at end of file diff --git a/api-reference/client-api/connection-management.mdx b/api-reference/client-api/connection-management.mdx new file mode 100644 index 0000000..844f896 --- /dev/null +++ b/api-reference/client-api/connection-management.mdx @@ -0,0 +1,8 @@ +--- +title: "Connection Management" +description: "Manage MCP client connections" +--- + +# Connection Management + +Manage MCP client connections diff --git a/api-reference/client-api/resource-consumption.mdx b/api-reference/client-api/resource-consumption.mdx new file mode 100644 index 0000000..39388bf --- /dev/null +++ b/api-reference/client-api/resource-consumption.mdx @@ -0,0 +1,8 @@ +--- +title: "Resource Consumption" +description: "Work with MCP resources from clients" +--- + +# Resource Consumption + +Work with MCP resources from clients diff --git a/api-reference/client-api/tool-invocation.mdx b/api-reference/client-api/tool-invocation.mdx new file mode 100644 index 0000000..a76a659 --- /dev/null +++ b/api-reference/client-api/tool-invocation.mdx @@ -0,0 +1,8 @@ +--- +title: "Tool Invocation" +description: "Invoke MCP tools from clients" +--- + +# Tool Invocation + +Invoke MCP tools from clients diff --git a/api-reference/endpoint/create.mdx b/api-reference/endpoint/create.mdx deleted file mode 100644 index 5689f1b..0000000 --- a/api-reference/endpoint/create.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Create Plant' -openapi: 'POST /plants' ---- diff --git a/api-reference/endpoint/delete.mdx b/api-reference/endpoint/delete.mdx deleted file mode 100644 index 657dfc8..0000000 --- a/api-reference/endpoint/delete.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Delete Plant' -openapi: 'DELETE /plants/{id}' ---- diff --git a/api-reference/endpoint/get.mdx b/api-reference/endpoint/get.mdx deleted file mode 100644 index 56aa09e..0000000 --- a/api-reference/endpoint/get.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Get Plants' -openapi: 'GET /plants' ---- diff --git a/api-reference/error-handling.mdx b/api-reference/error-handling.mdx new file mode 100644 index 0000000..b5932b7 --- /dev/null +++ b/api-reference/error-handling.mdx @@ -0,0 +1,8 @@ +--- +title: "Error Handling" +description: "Handle errors in MCP implementations" +--- + +# Error Handling + +Handle errors in MCP implementations diff --git a/api-reference/introduction.mdx b/api-reference/introduction.mdx deleted file mode 100644 index c835b78..0000000 --- a/api-reference/introduction.mdx +++ /dev/null @@ -1,33 +0,0 @@ ---- -title: 'Introduction' -description: 'Example section for showcasing API endpoints' ---- - - - If you're not looking to build API reference documentation, you can delete - this section by removing the api-reference folder. - - -## Welcome - -There are two ways to build API documentation: [OpenAPI](https://mintlify.com/docs/api-playground/openapi/setup) and [MDX components](https://mintlify.com/docs/api-playground/mdx/configuration). For the starter kit, we are using the following OpenAPI specification. - - - View the OpenAPI specification file - - -## Authentication - -All API endpoints are authenticated using Bearer tokens and picked up from the specification file. - -```json -"security": [ - { - "bearerAuth": [] - } -] -``` diff --git a/api-reference/message-types.mdx b/api-reference/message-types.mdx new file mode 100644 index 0000000..fe9cff8 --- /dev/null +++ b/api-reference/message-types.mdx @@ -0,0 +1,8 @@ +--- +title: "Message Types" +description: "Complete reference of MCP message formats" +--- + +# Message Types + +Complete reference of MCP message formats diff --git a/api-reference/openapi.json b/api-reference/openapi.json deleted file mode 100644 index b1509be..0000000 --- a/api-reference/openapi.json +++ /dev/null @@ -1,195 +0,0 @@ -{ - "openapi": "3.0.1", - "info": { - "title": "OpenAPI Plant Store", - "description": "A sample API that uses a plant store as an example to demonstrate features in the OpenAPI specification", - "license": { - "name": "MIT" - }, - "version": "1.0.0" - }, - "servers": [ - { - "url": "http://sandbox.mintlify.com" - } - ], - "security": [ - { - "bearerAuth": [] - } - ], - "paths": { - "/plants": { - "get": { - "description": "Returns all plants from the system that the user has access to", - "parameters": [ - { - "name": "limit", - "in": "query", - "description": "The maximum number of results to return", - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Plant response", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Plant" - } - } - } - } - }, - "400": { - "description": "Unexpected error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - } - } - }, - "post": { - "description": "Creates a new plant in the store", - "requestBody": { - "description": "Plant to add to the store", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/NewPlant" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "plant response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Plant" - } - } - } - }, - "400": { - "description": "unexpected error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - } - } - } - }, - "/plants/{id}": { - "delete": { - "description": "Deletes a single plant based on the ID supplied", - "parameters": [ - { - "name": "id", - "in": "path", - "description": "ID of plant to delete", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "204": { - "description": "Plant deleted", - "content": {} - }, - "400": { - "description": "unexpected error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - } - } - } - } - }, - "components": { - "schemas": { - "Plant": { - "required": [ - "name" - ], - "type": "object", - "properties": { - "name": { - "description": "The name of the plant", - "type": "string" - }, - "tag": { - "description": "Tag to specify the type", - "type": "string" - } - } - }, - "NewPlant": { - "allOf": [ - { - "$ref": "#/components/schemas/Plant" - }, - { - "required": [ - "id" - ], - "type": "object", - "properties": { - "id": { - "description": "Identification number of the plant", - "type": "integer", - "format": "int64" - } - } - } - ] - }, - "Error": { - "required": [ - "error", - "message" - ], - "type": "object", - "properties": { - "error": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - } - } - } - }, - "securitySchemes": { - "bearerAuth": { - "type": "http", - "scheme": "bearer" - } - } - } -} \ No newline at end of file diff --git a/api-reference/protocol-overview.mdx b/api-reference/protocol-overview.mdx new file mode 100644 index 0000000..b58d90a --- /dev/null +++ b/api-reference/protocol-overview.mdx @@ -0,0 +1,8 @@ +--- +title: "Protocol Overview" +description: "Understanding the Model Context Protocol" +--- + +# Protocol Overview + +Understanding the Model Context Protocol diff --git a/api-reference/python/class-reference.mdx b/api-reference/python/class-reference.mdx new file mode 100644 index 0000000..43739a4 --- /dev/null +++ b/api-reference/python/class-reference.mdx @@ -0,0 +1,8 @@ +--- +title: "Python Class Reference" +description: "Complete Python SDK class documentation" +--- + +# Python Class Reference + +Complete Python SDK class documentation diff --git a/api-reference/python/examples.mdx b/api-reference/python/examples.mdx new file mode 100644 index 0000000..94c751c --- /dev/null +++ b/api-reference/python/examples.mdx @@ -0,0 +1,8 @@ +--- +title: "Python Examples" +description: "Example Python implementations" +--- + +# Python Examples + +Example Python implementations diff --git a/api-reference/python/type-hints.mdx b/api-reference/python/type-hints.mdx new file mode 100644 index 0000000..d037e47 --- /dev/null +++ b/api-reference/python/type-hints.mdx @@ -0,0 +1,8 @@ +--- +title: "Python Type Hints" +description: "Python type system documentation" +--- + +# Python Type Hints + +Python type system documentation diff --git a/api-reference/server-api/event-handling.mdx b/api-reference/server-api/event-handling.mdx new file mode 100644 index 0000000..dab1bc3 --- /dev/null +++ b/api-reference/server-api/event-handling.mdx @@ -0,0 +1,8 @@ +--- +title: "Event Handling" +description: "Handle events in your MCP server" +--- + +# Event Handling + +Handle events in your MCP server diff --git a/api-reference/server-api/resource-management.mdx b/api-reference/server-api/resource-management.mdx new file mode 100644 index 0000000..34de1ab --- /dev/null +++ b/api-reference/server-api/resource-management.mdx @@ -0,0 +1,8 @@ +--- +title: "Resource Management" +description: "Manage resources in your MCP server" +--- + +# Resource Management + +Manage resources in your MCP server diff --git a/api-reference/server-api/tool-implementation.mdx b/api-reference/server-api/tool-implementation.mdx new file mode 100644 index 0000000..0ede2a0 --- /dev/null +++ b/api-reference/server-api/tool-implementation.mdx @@ -0,0 +1,8 @@ +--- +title: "Tool Implementation" +description: "Implement tools in your MCP server" +--- + +# Tool Implementation + +Implement tools in your MCP server diff --git a/api-reference/typescript/class-reference.mdx b/api-reference/typescript/class-reference.mdx new file mode 100644 index 0000000..c08a40d --- /dev/null +++ b/api-reference/typescript/class-reference.mdx @@ -0,0 +1,8 @@ +--- +title: "TypeScript Class Reference" +description: "Complete TypeScript SDK class documentation" +--- + +# TypeScript Class Reference + +Complete TypeScript SDK class documentation diff --git a/api-reference/typescript/examples.mdx b/api-reference/typescript/examples.mdx new file mode 100644 index 0000000..7b5b7b5 --- /dev/null +++ b/api-reference/typescript/examples.mdx @@ -0,0 +1,8 @@ +--- +title: "TypeScript Examples" +description: "Example TypeScript implementations" +--- + +# TypeScript Examples + +Example TypeScript implementations diff --git a/api-reference/typescript/type-definitions.mdx b/api-reference/typescript/type-definitions.mdx new file mode 100644 index 0000000..cebeb24 --- /dev/null +++ b/api-reference/typescript/type-definitions.mdx @@ -0,0 +1,8 @@ +--- +title: "TypeScript Type Definitions" +description: "TypeScript type system documentation" +--- + +# TypeScript Type Definitions + +TypeScript type system documentation diff --git a/create-docs.sh b/create-docs.sh new file mode 100644 index 0000000..03dda90 --- /dev/null +++ b/create-docs.sh @@ -0,0 +1,75 @@ +#!/bin/bash + +# Create base directories +mkdir -p docs/{guides,recipes,deployment,api,server-api,client-api,typescript,python} + +# Function to create an .mdx file with frontmatter +create_mdx() { + local filepath=$1 + local title=$2 + local description=$3 + + echo "Creating $filepath..." + cat > "$filepath" < - **Prerequisite**: Please install Node.js (version 19 or higher) before proceeding. - - -Follow these steps to install and run Mintlify on your operating system: - -**Step 1**: Install Mintlify: - - - - ```bash npm - npm i -g mintlify - ``` - -```bash yarn -yarn global add mintlify -``` - - - -**Step 2**: Navigate to the docs directory (where the `mint.json` file is located) and execute the following command: - -```bash -mintlify dev -``` - -A local preview of your documentation will be available at `http://localhost:3000`. - -### Custom Ports - -By default, Mintlify uses port 3000. You can customize the port Mintlify runs on by using the `--port` flag. To run Mintlify on port 3333, for instance, use this command: - -```bash -mintlify dev --port 3333 -``` - -If you attempt to run Mintlify on a port that's already in use, it will use the next available port: - -```md -Port 3000 is already in use. Trying 3001 instead. -``` - -## Mintlify Versions - -Please note that each CLI release is associated with a specific version of Mintlify. If your local website doesn't align with the production version, please update the CLI: - - - -```bash npm -npm i -g mintlify@latest -``` - -```bash yarn -yarn global upgrade mintlify -``` - - - -## Validating Links - -The CLI can assist with validating reference links made in your documentation. To identify any broken links, use the following command: - -```bash -mintlify broken-links -``` - -## Deployment - - - Unlimited editors available under the [Pro - Plan](https://mintlify.com/pricing) and above. - - -If the deployment is successful, you should see the following: - - - - - -## Code Formatting - -We suggest using extensions on your IDE to recognize and format MDX. If you're a VSCode user, consider the [MDX VSCode extension](https://marketplace.visualstudio.com/items?itemName=unifiedjs.vscode-mdx) for syntax highlighting, and [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) for code formatting. - -## Troubleshooting - - - - - This may be due to an outdated version of node. Try the following: - 1. Remove the currently-installed version of mintlify: `npm remove -g mintlify` - 2. Upgrade to Node v19 or higher. - 3. Reinstall mintlify: `npm install -g mintlify` - - - - - Solution: Go to the root of your device and delete the \~/.mintlify folder. Afterwards, run `mintlify dev` again. - - - -Curious about what changed in the CLI version? [Check out the CLI changelog.](https://www.npmjs.com/package/mintlify?activeTab=versions) diff --git a/docs/deployment/configuration.mdx b/docs/deployment/configuration.mdx new file mode 100644 index 0000000..91b7311 --- /dev/null +++ b/docs/deployment/configuration.mdx @@ -0,0 +1,5 @@ +--- +title: "Configuration" +description: "Configure MCP servers for production" +--- + diff --git a/docs/deployment/environment-setup.mdx b/docs/deployment/environment-setup.mdx new file mode 100644 index 0000000..102a91f --- /dev/null +++ b/docs/deployment/environment-setup.mdx @@ -0,0 +1,4 @@ +--- +title: "Environment Setup" +description: "Set up your production environment" +--- \ No newline at end of file diff --git a/docs/deployment/monitoring.mdx b/docs/deployment/monitoring.mdx new file mode 100644 index 0000000..72aa561 --- /dev/null +++ b/docs/deployment/monitoring.mdx @@ -0,0 +1,8 @@ +--- +title: "Monitoring" +description: "Monitor your MCP servers in production" +--- + +# Monitoring + +Monitor your MCP servers in production diff --git a/docs/development.mdx b/docs/development.mdx new file mode 100644 index 0000000..e69de29 diff --git a/docs/guides/first-mcp-server.mdx b/docs/guides/first-mcp-server.mdx new file mode 100644 index 0000000..f2df732 --- /dev/null +++ b/docs/guides/first-mcp-server.mdx @@ -0,0 +1,8 @@ +--- +title: "Your First MCP Server" +description: "Build a complete MCP server from scratch" +--- + +# Your First MCP Server + +Build a complete MCP server from scratch diff --git a/docs/guides/implementing-tools.mdx b/docs/guides/implementing-tools.mdx new file mode 100644 index 0000000..da25884 --- /dev/null +++ b/docs/guides/implementing-tools.mdx @@ -0,0 +1,8 @@ +--- +title: "Implementing Tools" +description: "Create tools that LLMs can invoke" +--- + +# Implementing Tools + +Create tools that LLMs can invoke diff --git a/docs/guides/integrating-with-llm.mdx b/docs/guides/integrating-with-llm.mdx new file mode 100644 index 0000000..a801e53 --- /dev/null +++ b/docs/guides/integrating-with-llm.mdx @@ -0,0 +1,385 @@ +--- +title: "Integrating MCP into Your LLM Application" +description: 'Learn how to integrate the Model Context Protocol (MCP) into your LLM-powered applications' +--- + +The Model Context Protocol (MCP) enables seamless integration between LLM applications and various data sources and tools. This guide will walk you through integrating MCP into your own LLM-powered chatbot application. + +## Our Example Chatbot + +For this guide, we'll be working with a hypothetical customer service chatbot for a software company. Our chatbot currently: + +- Uses an LLM API (like Anthropic's Claude API) to generate responses +- Maintains conversation history in memory +- Has basic error handling and retry logic +- Runs as a web service that customers interact with through a REST API + +However, our chatbot faces some limitations: +- It can't access real-time product documentation or knowledge base articles +- It can't look up customer information or ticket history +- It can't perform actions like creating tickets or updating customer records +- It doesn't stay up-to-date with product changes and new features + +By integrating MCP, we'll enhance our chatbot to: +- Access documentation and knowledge base articles as contextual resources +- Look up customer information through a CRM integration +- Create and update support tickets through a ticketing system integration +- Get real-time updates when documentation or product information changes + +Let's get started! + +## Prerequisites + +1. Clone the example MCP servers: +```bash +git clone https://github.com/modelcontextprotocol/example-servers.git +cd example-servers +npm install +``` + +2. Install the MCP SDK in your chatbot project: +```bash +npm install @modelcontextprotocol/sdk +``` + +## Starting Point: Our Basic Chatbot + +Here's our starting chatbot implementation that we'll enhance with MCP: + +```typescript +interface Message { + role: 'user' | 'assistant'; + content: string; +} + +class CustomerServiceBot { + private conversation: Message[] = []; + private llmClient: LLMClient; // Your LLM API client + + constructor(llmClient: LLMClient) { + this.llmClient = llmClient; + } + + async handleMessage(message: string): Promise { + // Add user message to conversation + this.conversation.push({ role: 'user', content: message }); + + // Get LLM response + const response = await this.llmClient.complete({ + messages: this.conversation, + maxTokens: 1000 + }); + + // Add assistant response to conversation + this.conversation.push({ role: 'assistant', content: response }); + + return response; + } +} +``` + +## Step 1: Adding Documentation Context + +First, let's enhance our chatbot to incorporate product documentation. We'll use the example PostgreSQL server which can store and serve our docs. + +```typescript +import { Client } from "@modelcontextprotocol/sdk/client"; +import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio"; +import { + ListResourcesResultSchema, + ReadResourceResultSchema +} from "@modelcontextprotocol/sdk/types"; + +class EnhancedCustomerServiceBot { + private conversation: Message[] = []; + private llmClient: LLMClient; + private mcpClient: Client; + + constructor(llmClient: LLMClient) { + this.llmClient = llmClient; + + // Initialize MCP client + this.mcpClient = new Client({ + name: "customer-service-bot", + version: "1.0.0" + }); + } + + async initialize() { + // Connect to PostgreSQL server for documentation + const transport = new StdioClientTransport({ + command: "./example-servers/postgres/index.js", + args: ["postgres://localhost/docs"] // Your docs database + }); + await this.mcpClient.connect(transport); + } + + async getRelevantDocs(message: string): Promise { + // List available documentation resources + const { resources } = await this.mcpClient.request( + { method: "resources/list" }, + ListResourcesResultSchema + ); + + // Read each documentation resource + const docs = await Promise.all( + resources.map(async (resource) => { + const { contents } = await this.mcpClient.request( + { + method: "resources/read", + params: { uri: resource.uri } + }, + ReadResourceResultSchema + ); + return contents[0].text; + }) + ); + + return docs.join("\n\n"); + } + + async handleMessage(message: string): Promise { + // Get relevant documentation + const docs = await this.getRelevantDocs(message); + + // Build prompt with documentation context + const prompt = ` + Here is relevant documentation about our product: + ${docs} + + Please use this information to help answer the customer's question. + + Customer: ${message} + `; + + // Add user message to conversation + this.conversation.push({ role: 'user', content: message }); + + // Get LLM response with documentation context + const response = await this.llmClient.complete({ + messages: [...this.conversation, { role: 'user', content: prompt }], + maxTokens: 1000 + }); + + // Add assistant response to conversation + this.conversation.push({ role: 'assistant', content: response }); + + return response; + } +} +``` + +## Step 2: Adding Ticket Management + +Now let's add the ability to create and update support tickets. We'll use the example tools server for this: + +```typescript +import { CallToolResultSchema } from "@modelcontextprotocol/sdk/types"; + +interface Ticket { + id: string; + subject: string; + description: string; + status: 'open' | 'closed'; +} + +class EnhancedCustomerServiceBot { + // ... previous code ... + + async createTicket(subject: string, description: string): Promise { + const result = await this.mcpClient.request( + { + method: "tools/call", + params: { + name: "create_ticket", + arguments: { + subject, + description + } + } + }, + CallToolResultSchema + ); + + return result.toolResult as Ticket; + } + + async handleMessage(message: string): Promise { + // Get relevant documentation + const docs = await this.getRelevantDocs(message); + + // Build prompt with documentation context and ticket creation ability + const prompt = ` + Here is relevant documentation about our product: + ${docs} + + You can create support tickets when needed using the createTicket function. + Only create tickets for actual technical issues that need follow-up. + + Customer: ${message} + `; + + // Get LLM response + const response = await this.llmClient.complete({ + messages: [...this.conversation, { role: 'user', content: prompt }], + maxTokens: 1000, + tools: [{ + name: 'createTicket', + description: 'Create a support ticket for technical issues', + parameters: { + subject: 'string', + description: 'string' + } + }] + }); + + // Check if the LLM wants to create a ticket + if (response.toolCalls?.length > 0) { + const call = response.toolCalls[0]; + const ticket = await this.createTicket( + call.arguments.subject, + call.arguments.description + ); + + // Add ticket creation to conversation + this.conversation.push({ + role: 'system', + content: `Created ticket #${ticket.id}: ${ticket.subject}` + }); + } + + // Add messages to conversation + this.conversation.push({ role: 'user', content: message }); + this.conversation.push({ role: 'assistant', content: response.content }); + + return response.content; + } +} +``` + +## Step 3: Real-time Documentation Updates + +Finally, let's make our chatbot aware of documentation changes in real-time: + +```typescript +class EnhancedCustomerServiceBot { + // ... previous code ... + + async initialize() { + // Connect to PostgreSQL server + const transport = new StdioClientTransport({ + command: "./example-servers/postgres/index.js", + args: ["postgres://localhost/docs"] + }); + await this.mcpClient.connect(transport); + + // Subscribe to documentation updates + const { resources } = await this.mcpClient.request( + { method: "resources/list" }, + ListResourcesResultSchema + ); + + for (const resource of resources) { + await this.mcpClient.request( + { + method: "resources/subscribe", + params: { uri: resource.uri } + }, + EmptyResultSchema + ); + } + + // Handle update notifications + this.mcpClient.setNotificationHandler( + ResourceUpdatedNotificationSchema, + async (notification) => { + console.log(`Documentation updated: ${notification.params.uri}`); + // Optionally clear any cached documentation + } + ); + } +} +``` + +## Using the Enhanced Chatbot + +Here's how to use our enhanced chatbot: + +```typescript +const bot = new EnhancedCustomerServiceBot(llmClient); +await bot.initialize(); + +// Example conversation +const response1 = await bot.handleMessage( + "How do I reset my password?" +); +// Bot responds with information from documentation + +const response2 = await bot.handleMessage( + "I can't log in even after resetting my password" +); +// Bot creates a ticket and responds with next steps + +``` + +## Error Handling + +Add robust error handling around MCP operations: + +```typescript +class EnhancedCustomerServiceBot { + // ... previous code ... + + async getRelevantDocs(message: string): Promise { + try { + const { resources } = await this.mcpClient.request( + { method: "resources/list" }, + ListResourcesResultSchema + ); + + const docs = await Promise.all( + resources.map(async (resource) => { + try { + const { contents } = await this.mcpClient.request( + { + method: "resources/read", + params: { uri: resource.uri } + }, + ReadResourceResultSchema + ); + return contents[0].text; + } catch (error) { + console.error(`Failed to read resource ${resource.uri}:`, error); + return ""; // Skip failed resources + } + }) + ); + + return docs.join("\n\n"); + } catch (error) { + console.error("Failed to list resources:", error); + return ""; // Fallback to no documentation + } + } +} +``` + +## Next Steps + +Now that you've enhanced your chatbot with MCP, you can: + +1. Add more integrations: + - Connect to your actual documentation system + - Integrate with your production ticketing system + - Add CRM integration for customer context + +2. Improve the implementation: + - Add better documentation relevance filtering + - Implement more sophisticated prompt engineering + - Add authentication and access control + - Add monitoring and logging + - Implement caching for frequently accessed resources + +3. Consider building custom MCP servers for your specific needs + +The example servers repository includes other servers you can experiment with, and you can build your own servers to expose custom functionality to your chatbot. \ No newline at end of file diff --git a/docs/guides/security-best-practices.mdx b/docs/guides/security-best-practices.mdx new file mode 100644 index 0000000..1ccf011 --- /dev/null +++ b/docs/guides/security-best-practices.mdx @@ -0,0 +1,8 @@ +--- +title: "Security Best Practices" +description: "Secure your MCP implementations" +--- + +# Security Best Practices + +Secure your MCP implementations diff --git a/docs/guides/testing-debugging.mdx b/docs/guides/testing-debugging.mdx new file mode 100644 index 0000000..a936680 --- /dev/null +++ b/docs/guides/testing-debugging.mdx @@ -0,0 +1,8 @@ +--- +title: "Testing and Debugging" +description: "Test and debug your MCP servers effectively" +--- + +# Testing and Debugging + +Test and debug your MCP servers effectively diff --git a/docs/guides/working-with-resources.mdx b/docs/guides/working-with-resources.mdx new file mode 100644 index 0000000..f77ad53 --- /dev/null +++ b/docs/guides/working-with-resources.mdx @@ -0,0 +1,8 @@ +--- +title: "Working with Resources" +description: "Learn how to expose and consume data through MCP" +--- + +# Working with Resources + +Learn how to expose and consume data through MCP diff --git a/docs/installation.mdx b/docs/installation.mdx new file mode 100644 index 0000000..66ffc35 --- /dev/null +++ b/docs/installation.mdx @@ -0,0 +1,160 @@ +--- +title: "Installation" +description: "Get started with Model Context Protocol (MCP) by installing the SDK for your preferred language" +--- + + + MCP supports both TypeScript and Python implementations. Choose the one that best fits your project. + + + + + + + Install the TypeScript SDK using npm: + ```bash + npm install @modelcontextprotocol/sdk + ``` + + + Install the Python SDK using pip: + ```bash + pip install modelcontextprotocol + ``` + + + + + + Verify your installation by running a simple test: + + + ```typescript typescript-test.ts + import { Client } from "@modelcontextprotocol/sdk"; + + const client = new Client({ + name: "test-client", + version: "0.1.0" + }); + console.log("MCP SDK installed successfully!"); + ``` + + ```python python-test.py + from modelcontextprotocol import Client + + client = Client( + name="test-client", + version="0.1.0" + ) + print("MCP SDK installed successfully!") + ``` + + + + + + For local development, you'll need Node.js 18+ for TypeScript or Python 3.8+ for Python. + + + Install the MCP Inspector for testing and debugging your implementations: + ```bash + npm install -g @modelcontextprotocol/inspector + ``` + + + +## System Requirements + + + + - Node.js 18 or higher + - npm 7 or higher + - TypeScript 4.7 or higher (for TypeScript users) + + Optional development tools: + - VS Code with TypeScript plugin + - ESLint for code quality + + + + - Python 3.8 or higher + - pip 20.0 or higher + - virtualenv (recommended) + + Optional development tools: + - VS Code with Python extension + - pylint for code quality + + + + MCP supports all major operating systems: + - Windows 10/11 + - macOS 10.15+ + - Linux (major distributions) + + + +## Architecture Overview + + + + + +```mermaid +flowchart LR + A[LLM Application] --> B[MCP Client] + B --> C[MCP Server] + C --> D[(External Resource)] + + style A fill:#e0f4ff,stroke:#0077cc,stroke-width:2px + style B fill:#fff4e0,stroke:#ff8c00,stroke-width:2px + style C fill:#e0ffe0,stroke:#2d862d,stroke-width:2px + style D fill:#ffe0e0,stroke:#cc0000,stroke-width:2px + + classDef default fill:#f9f9f9,stroke:#333,stroke-width:1px + +## Next Steps + + + Build your first MCP integration in under 5 minutes + + + Explore pre-built MCP servers for common use cases + + + Dive into the complete API documentation + + + + Join our [Discord community](https://discord.gg/mcp) for help and discussions about MCP development. + + +## Troubleshooting Common Issues + + + + If you encounter version conflicts, ensure all your dependencies are up to date: + ```bash + # For TypeScript + npm update @modelcontextprotocol/sdk +Copy# For Python +pip install --upgrade modelcontextprotocol +``` + + + If you're having trouble connecting to MCP servers: + 1. Check your network configuration + 2. Verify the server is running + 3. Ensure your firewall isn't blocking connections + 4. Check the server logs for errors + + + Common build errors and their solutions: + - TypeScript type errors: Update your @types dependencies + - Python import errors: Check your PYTHONPATH + - Missing dependencies: Run package manager install commands + + + + Remember to keep your SDKs updated to the latest version for security patches and new features. + diff --git a/docs/key-concepts.mdx b/docs/key-concepts.mdx new file mode 100644 index 0000000..691ab1b --- /dev/null +++ b/docs/key-concepts.mdx @@ -0,0 +1,12 @@ +--- +title: "Key Concepts" +description: "Learn the core concepts behind the Model Context Protocol (MCP) and how they work together" +--- + + + This guide provides a high-level overview of MCP's core concepts. For detailed implementation guides, check out our tutorials section. + + +The Model Context Protocol (MCP) enables seamless integration between LLM applications and external data sources or tools. Let's break down the key concepts: + + diff --git a/docs/recipes/api-integration.mdx b/docs/recipes/api-integration.mdx new file mode 100644 index 0000000..f3787b0 --- /dev/null +++ b/docs/recipes/api-integration.mdx @@ -0,0 +1,8 @@ +--- +title: "API Integration" +description: "Wrap external APIs with MCP" +--- + +# API Integration + +Wrap external APIs with MCP diff --git a/docs/recipes/database-integration.mdx b/docs/recipes/database-integration.mdx new file mode 100644 index 0000000..dbcf630 --- /dev/null +++ b/docs/recipes/database-integration.mdx @@ -0,0 +1,8 @@ +--- +title: "Database Integration" +description: "Connect databases to your LLM through MCP" +--- + +# Database Integration + +Connect databases to your LLM through MCP diff --git a/docs/recipes/local-files.mdx b/docs/recipes/local-files.mdx new file mode 100644 index 0000000..fb592b4 --- /dev/null +++ b/docs/recipes/local-files.mdx @@ -0,0 +1,8 @@ +--- +title: "Local File Access" +description: "Implement local file access in MCP" +--- + +# Local File Access + +Implement local file access in MCP diff --git a/docs/recipes/realtime-updates.mdx b/docs/recipes/realtime-updates.mdx new file mode 100644 index 0000000..a7d2b58 --- /dev/null +++ b/docs/recipes/realtime-updates.mdx @@ -0,0 +1,8 @@ +--- +title: "Real-time Updates" +description: "Handle live data updates in MCP" +--- + +# Real-time Updates + +Handle live data updates in MCP diff --git a/essentials/code.mdx b/essentials/code.mdx deleted file mode 100644 index d2a462a..0000000 --- a/essentials/code.mdx +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: 'Code Blocks' -description: 'Display inline code and code blocks' -icon: 'code' ---- - -## Basic - -### Inline Code - -To denote a `word` or `phrase` as code, enclose it in backticks (`). - -``` -To denote a `word` or `phrase` as code, enclose it in backticks (`). -``` - -### Code Block - -Use [fenced code blocks](https://www.markdownguide.org/extended-syntax/#fenced-code-blocks) by enclosing code in three backticks and follow the leading ticks with the programming language of your snippet to get syntax highlighting. Optionally, you can also write the name of your code after the programming language. - -```java HelloWorld.java -class HelloWorld { - public static void main(String[] args) { - System.out.println("Hello, World!"); - } -} -``` - -````md -```java HelloWorld.java -class HelloWorld { - public static void main(String[] args) { - System.out.println("Hello, World!"); - } -} -``` -```` diff --git a/essentials/images.mdx b/essentials/images.mdx deleted file mode 100644 index 60ad42d..0000000 --- a/essentials/images.mdx +++ /dev/null @@ -1,59 +0,0 @@ ---- -title: 'Images and Embeds' -description: 'Add image, video, and other HTML elements' -icon: 'image' ---- - - - -## Image - -### Using Markdown - -The [markdown syntax](https://www.markdownguide.org/basic-syntax/#images) lets you add images using the following code - -```md -![title](/path/image.jpg) -``` - -Note that the image file size must be less than 5MB. Otherwise, we recommend hosting on a service like [Cloudinary](https://cloudinary.com/) or [S3](https://aws.amazon.com/s3/). You can then use that URL and embed. - -### Using Embeds - -To get more customizability with images, you can also use [embeds](/writing-content/embed) to add images - -```html - -``` - -## Embeds and HTML elements - - - -
- - - -Mintlify supports [HTML tags in Markdown](https://www.markdownguide.org/basic-syntax/#html). This is helpful if you prefer HTML tags to Markdown syntax, and lets you create documentation with infinite flexibility. - - - -### iFrames - -Loads another HTML page within the document. Most commonly used for embedding videos. - -```html - -``` diff --git a/essentials/markdown.mdx b/essentials/markdown.mdx deleted file mode 100644 index c8ad9c1..0000000 --- a/essentials/markdown.mdx +++ /dev/null @@ -1,88 +0,0 @@ ---- -title: 'Markdown Syntax' -description: 'Text, title, and styling in standard markdown' -icon: 'text-size' ---- - -## Titles - -Best used for section headers. - -```md -## Titles -``` - -### Subtitles - -Best use to subsection headers. - -```md -### Subtitles -``` - - - -Each **title** and **subtitle** creates an anchor and also shows up on the table of contents on the right. - - - -## Text Formatting - -We support most markdown formatting. Simply add `**`, `_`, or `~` around text to format it. - -| Style | How to write it | Result | -| ------------- | ----------------- | --------------- | -| Bold | `**bold**` | **bold** | -| Italic | `_italic_` | _italic_ | -| Strikethrough | `~strikethrough~` | ~strikethrough~ | - -You can combine these. For example, write `**_bold and italic_**` to get **_bold and italic_** text. - -You need to use HTML to write superscript and subscript text. That is, add `` or `` around your text. - -| Text Size | How to write it | Result | -| ----------- | ------------------------ | ---------------------- | -| Superscript | `superscript` | superscript | -| Subscript | `subscript` | subscript | - -## Linking to Pages - -You can add a link by wrapping text in `[]()`. You would write `[link to google](https://google.com)` to [link to google](https://google.com). - -Links to pages in your docs need to be root-relative. Basically, you should include the entire folder path. For example, `[link to text](/writing-content/text)` links to the page "Text" in our components section. - -Relative links like `[link to text](../text)` will open slower because we cannot optimize them as easily. - -## Blockquotes - -### Singleline - -To create a blockquote, add a `>` in front of a paragraph. - -> Dorothy followed her through many of the beautiful rooms in her castle. - -```md -> Dorothy followed her through many of the beautiful rooms in her castle. -``` - -### Multiline - -> Dorothy followed her through many of the beautiful rooms in her castle. -> -> The Witch bade her clean the pots and kettles and sweep the floor and keep the fire fed with wood. - -```md -> Dorothy followed her through many of the beautiful rooms in her castle. -> -> The Witch bade her clean the pots and kettles and sweep the floor and keep the fire fed with wood. -``` - -### LaTeX - -Mintlify supports [LaTeX](https://www.latex-project.org) through the Latex component. - -8 x (vk x H1 - H2) = (0,1) - -```md -8 x (vk x H1 - H2) = (0,1) -``` diff --git a/essentials/navigation.mdx b/essentials/navigation.mdx deleted file mode 100644 index ca44bb6..0000000 --- a/essentials/navigation.mdx +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: 'Navigation' -description: 'The navigation field in mint.json defines the pages that go in the navigation menu' -icon: 'map' ---- - -The navigation menu is the list of links on every website. - -You will likely update `mint.json` every time you add a new page. Pages do not show up automatically. - -## Navigation syntax - -Our navigation syntax is recursive which means you can make nested navigation groups. You don't need to include `.mdx` in page names. - - - -```json Regular Navigation -"navigation": [ - { - "group": "Getting Started", - "pages": ["quickstart"] - } -] -``` - -```json Nested Navigation -"navigation": [ - { - "group": "Getting Started", - "pages": [ - "quickstart", - { - "group": "Nested Reference Pages", - "pages": ["nested-reference-page"] - } - ] - } -] -``` - - - -## Folders - -Simply put your MDX files in folders and update the paths in `mint.json`. - -For example, to have a page at `https://yoursite.com/your-folder/your-page` you would make a folder called `your-folder` containing an MDX file called `your-page.mdx`. - - - -You cannot use `api` for the name of a folder unless you nest it inside another folder. Mintlify uses Next.js which reserves the top-level `api` folder for internal server calls. A folder name such as `api-reference` would be accepted. - - - -```json Navigation With Folder -"navigation": [ - { - "group": "Group Name", - "pages": ["your-folder/your-page"] - } -] -``` - -## Hidden Pages - -MDX files not included in `mint.json` will not show up in the sidebar but are accessible through the search bar and by linking directly to them. diff --git a/essentials/reusable-snippets.mdx b/essentials/reusable-snippets.mdx deleted file mode 100644 index a0a5529..0000000 --- a/essentials/reusable-snippets.mdx +++ /dev/null @@ -1,110 +0,0 @@ ---- -title: Reusable Snippets -description: Reusable, custom snippets to keep content in sync -icon: 'recycle' ---- - -import SnippetIntro from '/snippets/snippet-intro.mdx'; - - - -## Creating a custom snippet - -**Pre-condition**: You must create your snippet file in the `snippets` directory. - - - Any page in the `snippets` directory will be treated as a snippet and will not - be rendered into a standalone page. If you want to create a standalone page - from the snippet, import the snippet into another file and call it as a - component. - - -### Default export - -1. Add content to your snippet file that you want to re-use across multiple - locations. Optionally, you can add variables that can be filled in via props - when you import the snippet. - -```mdx snippets/my-snippet.mdx -Hello world! This is my content I want to reuse across pages. My keyword of the -day is {word}. -``` - - - The content that you want to reuse must be inside the `snippets` directory in - order for the import to work. - - -2. Import the snippet into your destination file. - -```mdx destination-file.mdx ---- -title: My title -description: My Description ---- - -import MySnippet from '/snippets/path/to/my-snippet.mdx'; - -## Header - -Lorem impsum dolor sit amet. - - -``` - -### Reusable variables - -1. Export a variable from your snippet file: - -```mdx snippets/path/to/custom-variables.mdx -export const myName = 'my name'; - -export const myObject = { fruit: 'strawberries' }; -``` - -2. Import the snippet from your destination file and use the variable: - -```mdx destination-file.mdx ---- -title: My title -description: My Description ---- - -import { myName, myObject } from '/snippets/path/to/custom-variables.mdx'; - -Hello, my name is {myName} and I like {myObject.fruit}. -``` - -### Reusable components - -1. Inside your snippet file, create a component that takes in props by exporting - your component in the form of an arrow function. - -```mdx snippets/custom-component.mdx -export const MyComponent = ({ title }) => ( -
-

{title}

-

... snippet content ...

-
-); -``` - - - MDX does not compile inside the body of an arrow function. Stick to HTML - syntax when you can or use a default export if you need to use MDX. - - -2. Import the snippet into your destination file and pass in the props - -```mdx destination-file.mdx ---- -title: My title -description: My Description ---- - -import { MyComponent } from '/snippets/custom-component.mdx'; - -Lorem ipsum dolor sit amet. - - -``` diff --git a/essentials/settings.mdx b/essentials/settings.mdx deleted file mode 100644 index a8c158c..0000000 --- a/essentials/settings.mdx +++ /dev/null @@ -1,318 +0,0 @@ ---- -title: 'Global Settings' -description: 'Mintlify gives you complete control over the look and feel of your documentation using the mint.json file' -icon: 'gear' ---- - -Every Mintlify site needs a `mint.json` file with the core configuration settings. Learn more about the [properties](#properties) below. - -## Properties - - -Name of your project. Used for the global title. - -Example: `mintlify` - - - - - An array of groups with all the pages within that group - - - The name of the group. - - Example: `Settings` - - - - The relative paths to the markdown files that will serve as pages. - - Example: `["customization", "page"]` - - - - - - - - Path to logo image or object with path to "light" and "dark" mode logo images - - - Path to the logo in light mode - - - Path to the logo in dark mode - - - Where clicking on the logo links you to - - - - - - Path to the favicon image - - - - Hex color codes for your global theme - - - The primary color. Used for most often for highlighted content, section - headers, accents, in light mode - - - The primary color for dark mode. Used for most often for highlighted - content, section headers, accents, in dark mode - - - The primary color for important buttons - - - The color of the background in both light and dark mode - - - The hex color code of the background in light mode - - - The hex color code of the background in dark mode - - - - - - - - Array of `name`s and `url`s of links you want to include in the topbar - - - The name of the button. - - Example: `Contact us` - - - The url once you click on the button. Example: `https://mintlify.com/docs` - - - - - - - - - Link shows a button. GitHub shows the repo information at the url provided including the number of GitHub stars. - - - If `link`: What the button links to. - - If `github`: Link to the repository to load GitHub information from. - - - Text inside the button. Only required if `type` is a `link`. - - - - - - - Array of version names. Only use this if you want to show different versions - of docs with a dropdown in the navigation bar. - - - - An array of the anchors, includes the `icon`, `color`, and `url`. - - - The [Font Awesome](https://fontawesome.com/search?q=heart) icon used to feature the anchor. - - Example: `comments` - - - The name of the anchor label. - - Example: `Community` - - - The start of the URL that marks what pages go in the anchor. Generally, this is the name of the folder you put your pages in. - - - The hex color of the anchor icon background. Can also be a gradient if you pass an object with the properties `from` and `to` that are each a hex color. - - - Used if you want to hide an anchor until the correct docs version is selected. - - - Pass `true` if you want to hide the anchor until you directly link someone to docs inside it. - - - One of: "brands", "duotone", "light", "sharp-solid", "solid", or "thin" - - - - - - - Override the default configurations for the top-most anchor. - - - The name of the top-most anchor - - - Font Awesome icon. - - - One of: "brands", "duotone", "light", "sharp-solid", "solid", or "thin" - - - - - - An array of navigational tabs. - - - The name of the tab label. - - - The start of the URL that marks what pages go in the tab. Generally, this - is the name of the folder you put your pages in. - - - - - - Configuration for API settings. Learn more about API pages at [API Components](/api-playground/demo). - - - The base url for all API endpoints. If `baseUrl` is an array, it will enable for multiple base url - options that the user can toggle. - - - - - - The authentication strategy used for all API endpoints. - - - The name of the authentication parameter used in the API playground. - - If method is `basic`, the format should be `[usernameName]:[passwordName]` - - - The default value that's designed to be a prefix for the authentication input field. - - E.g. If an `inputPrefix` of `AuthKey` would inherit the default input result of the authentication field as `AuthKey`. - - - - - - Configurations for the API playground - - - - Whether the playground is showing, hidden, or only displaying the endpoint with no added user interactivity `simple` - - Learn more at the [playground guides](/api-playground/demo) - - - - - - Enabling this flag ensures that key ordering in OpenAPI pages matches the key ordering defined in the OpenAPI file. - - This behavior will soon be enabled by default, at which point this field will be deprecated. - - - - - - - A string or an array of strings of URL(s) or relative path(s) pointing to your - OpenAPI file. - - Examples: - - ```json Absolute - "openapi": "https://example.com/openapi.json" - ``` - ```json Relative - "openapi": "/openapi.json" - ``` - ```json Multiple - "openapi": ["https://example.com/openapi1.json", "/openapi2.json", "/openapi3.json"] - ``` - - - - - - An object of social media accounts where the key:property pair represents the social media platform and the account url. - - Example: - ```json - { - "x": "https://x.com/mintlify", - "website": "https://mintlify.com" - } - ``` - - - One of the following values `website`, `facebook`, `x`, `discord`, `slack`, `github`, `linkedin`, `instagram`, `hacker-news` - - Example: `x` - - - The URL to the social platform. - - Example: `https://x.com/mintlify` - - - - - - Configurations to enable feedback buttons - - - - Enables a button to allow users to suggest edits via pull requests - - - Enables a button to allow users to raise an issue about the documentation - - - - - - Customize the dark mode toggle. - - - Set if you always want to show light or dark mode for new users. When not - set, we default to the same mode as the user's operating system. - - - Set to true to hide the dark/light mode toggle. You can combine `isHidden` with `default` to force your docs to only use light or dark mode. For example: - - - ```json Only Dark Mode - "modeToggle": { - "default": "dark", - "isHidden": true - } - ``` - - ```json Only Light Mode - "modeToggle": { - "default": "light", - "isHidden": true - } - ``` - - - - - - - - - A background image to be displayed behind every page. See example with - [Infisical](https://infisical.com/docs) and [FRPC](https://frpc.io). - diff --git a/images/modelcontextprotocol.png b/images/modelcontextprotocol.png new file mode 100644 index 0000000000000000000000000000000000000000..8287430208a6ff1f08e4d1b8ccbf4b4a83bf2724 GIT binary patch literal 22447 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 Ll7(uIh@Jld#zI+e literal 0 HcmV?d00001 diff --git a/introduction.mdx b/introduction.mdx index 2589c0b..9f6743d 100644 --- a/introduction.mdx +++ b/introduction.mdx @@ -1,20 +1,12 @@ --- title: Introduction -description: 'Welcome to the home of your new documentation' +description: 'Introduction to the Model Context Protocol' --- -Hero Light -Hero Dark +The Model Context Protocol (MCP) is a protocol designed to enable LLM assistant surfaces to receive contextual information from specialized servers. Whether youโ€™re building an IDE coding assistant, a chat interface, or any other LLM-powered application, MCP provides a standardized way to obtain and utilize relevant context. -## Setting up + +## Get started The first step to world-class documentation is setting up your editing environments. diff --git a/logo/dark.png b/logo/dark.png new file mode 100644 index 0000000000000000000000000000000000000000..58156d11b6a0d276d8fec5c894776e4f5fbae45e GIT binary patch literal 1682 zcmbtV{Xf$Q93Kne5Xz)bVkWs|bDXDnnlk5MbguJIC@)XvY3R;1+Zac#gs3p{kgQZD zjC{HC5aG7HIE?a?wvljK7NgsYTYtm-@P5BvpU*GvU*50xy8!EVUPH}54Fm#dV7$w}VQrG7I@wrL?1oADnAayxcRz)KrKb; zyOByDkg_=j?e=|!f}m1>oBQ@q9+x6D{yF8JcO17jZXCCAwP)W)&=f6?cs2I_ zmTM}(`o=CEw|0b0qI{d96`E0cNe5h4f+cwj^&M|M(nQ>VH;WPl9HZjR$U?{V@%uT< z9c0?6lUbAk* z`1sUh8-lMLTUn&wAg;^ana~z8ARzc~8`^q zOs@Dl)iDTz9j}7$YGO~AU7b^WNd}ab_|&u7_4Nt7Is!@h9F>4;;B+R}30@9N1`=Ye zZQCJytkkQUUnuIpo$tmQT!FMMlVa4iNrR#nxv?1;BS|R|P`v21A8beWSKGl6ud( zh~_|%gwcG>WOP3FB`Wdym8aJ;^-x+jew~=?QLLdO5tp_Wv_3w9P0D?!mdlSQhVg?Qd1-dnpmlWOkc|?!_ec1y>no5Q?)Qx>STPlGo0@ zx1S}KccY~r@G7EosNJ{PD+Rdx2wV7p1ynxupi-?U}qhQEnSn8TOy^33H*D)nSAu^x$4do z_x2E@I{J4@5ha`U^)Dv6pxT=UmezdmCH&VD<8Wc)e#0a&;pk+-Q)b^mMslDIZ&TV{qfFKhrf zGqR&f&^pmJi3{oUz(bJCTs2L4U;i7C3xbD>m~lmY!0{y(2#IN=uRD>SCz^ED7%FNd zb3evAWb>G3!vDBuLE7c&t(obLv}UKZbayC#v;g}gNI&GLA%_%s1biEDOSO|k7Q*jOD85#Xr`Hj>2F-tUJua!w^SCPNs|lD!SgdrOamE%pIhcN60HqcA36 zTPm;?R$|Abkvl+i_;syRD`8|19XzAA4H)_u%_CWa%#yLyQa;rsQ{lEm9>;=4k<8}A z&An@T8_ritMsz!x>U!9NbFt3EXR$KwO7gCbzV?FBNbLe30=$<_{2O3W+8jfn5vNNj z_9MQ&>}$~Ighf|rL&*Rq3p)rYlchuY4G| zKQ-FH8VsU5Jbx+ZTnE@*6rgOC1pZS1t0~8Z6oL0prTM2EjZo}z+klQ-r^tjhv=7Ap zarL~7DiFr@eIWY>Err>AgSbHIs^Q6oF7@5qXW1zmU^BDdibw7~in@jRWtB9VCsE!5 zPPTdoXuHNNzna390@TiofzGByxXP@Bc#B6g`Cpa%rOuNF_Ul1rv|!RlSNVj1FrI#B Ix_boqKccxNU;qFB literal 0 HcmV?d00001 diff --git a/logo/light.png b/logo/light.png new file mode 100644 index 0000000000000000000000000000000000000000..37995098a5e30a71667fea824d087f7ad91bf28d GIT binary patch literal 1575 zcma)+|2q>19LHA=>u}X|@})Ff-P1x%qUp?+8ntB1w>*?Kwh$3+WeuC^+Nl#ROL5tx zYZkI-4a=9+;dYs<%rGn!v$nO#vT1EN{Re%X=k<9%@6QjP-`?-5;bDlimYXdB0KnSd z!$FZNIbRm?)?9j|O{TDi0Gbt!-3e_YpfZ1u|fZ&l>#Km(P$` zo~HWj8?004TPH5y@a>PU6?9AW0tjhvNprFkb#@aqwooMNcwEx-rrZ89_|NT{_Tlrm zkK4YOc-Jx9{2Y@%jE=E64PsRYKEveLu8mVe1T;jqbRlbZrf6I%!#{<6-fybWl+Z%bx*UEYtS8CZjZXgf&Jppszh zzT|+6yFsHfcw_o_(ny30%L{eR*0T?!+@g=zvG(vgOTPN#$jR?7Mf3gx};@= zBI`iIk6r>BN>X$0kr@1~=zf%&XnOtU|J2(%zgGR9vk z@Q*hh&uL^@JVRrV1UtoOo2T@Kb(K%ne1L1WGobyCpgLN(A*iYhvvD<3LwU;$ zKhvnW%Q2Q+9kYWtQHyC6Pt@CJ8G&X0?sJL~G?3&LiU_q;U>RoONCu=_HPyv^LZa8h zekU&d5S7HEy5794Jp*jXzG1EOE}mlRLF-!IH0r72rwV?ZcG?+l8b4{|@p%P3JSx2n z%*iym3^W)WQv|T2hVBrp3$#`t$x+^1j?Af81{dobIa3 z7@q;Nr4<=WGL`Nd8dIpMlOIqEUsK@@tv>w=u}-l|dxtGJgEbdZ-|_T4wUlzg^a<1W z`?g>dG4bgP<@2HL%gX_mdq1NK%`5kTSp9E{M&L3%(o*e%z_kQ+q7YcP)M@BU(Fpkr zT19mU81lP^DwgD=wSs?%8E65Qs_M4&W`tH1@v3wCTo)aCW2;~M<}R5%h>Cv_i4>Ec zJ$$F1jEiSLgnMu67o6+h8OCvo|wL{h@CKYOxUDInkIecZ9)FUfR$nWVH&CL`q9xnStY0*6& zxnP+wz@HiJIhwY>jo}KR%M;U>`yC}8^2$e=h?`|A>0&%XT5(-Ju!{*w@*#9R>|$a< z6vBIMA*7E@VE+WZfh};fN;1$#Ib%gzciQKzvCoAEtIadrkFc$Eqw77PC~`!0++?y+ z>$7~htPkhu-lNkI(fjo(TNnd&tiv`5N(CYjpj`^{N0d5SQ|r@wIh>4~7M?;0c%h2bZuHCIA2c literal 0 HcmV?d00001 diff --git a/mint.json b/mint.json index 2799bba..b93e86e 100644 --- a/mint.json +++ b/mint.json @@ -1,19 +1,16 @@ { "$schema": "https://mintlify.com/schema.json", - "name": "Starter Kit", + "name": "Model Context Protocol", "logo": { - "dark": "/logo/dark.svg", - "light": "/logo/light.svg" + "dark": "/logo/dark.png", + "light": "/logo/light.png" }, "favicon": "/favicon.svg", + "theme": "quill", "colors": { - "primary": "#0D9373", - "light": "#07C983", - "dark": "#0D9373", - "anchors": { - "from": "#0D9373", - "to": "#07C983" - } + "primary": "#09090b", + "light": "#FAFAFA", + "dark": "#09090b" }, "topbarLinks": [ { @@ -52,34 +49,78 @@ { "group": "Get Started", "pages": [ - "introduction", "quickstart", - "development" + "docs/installation", + "docs/key-concepts", + "docs/development" ] }, { - "group": "Essentials", + "group": "Guides", "pages": [ - "essentials/markdown", - "essentials/code", - "essentials/images", - "essentials/settings", - "essentials/navigation", - "essentials/reusable-snippets" + "docs/guides/first-mcp-server", + "docs/guides/integrating-with-llm", + "docs/guides/working-with-resources", + "docs/guides/implementing-tools", + "docs/guides/security-best-practices", + "docs/guides/testing-debugging" ] }, { - "group": "API Documentation", + "group": "Recipes", "pages": [ - "api-reference/introduction" + "docs/recipes/local-files", + "docs/recipes/database-integration", + "docs/recipes/api-integration", + "docs/recipes/realtime-updates" ] }, { - "group": "Endpoint Examples", + "group": "Deployment", "pages": [ - "api-reference/endpoint/get", - "api-reference/endpoint/create", - "api-reference/endpoint/delete" + "docs/deployment/environment-setup", + "docs/deployment/configuration", + "docs/deployment/monitoring" + ] + }, + { + "group": "API Reference", + "pages": [ + "api-reference/protocol-overview", + "api-reference/message-types", + "api-reference/error-handling" + ] + }, + { + "group": "Server APIs", + "pages": [ + "api-reference/server-api/resource-management", + "api-reference/server-api/tool-implementation", + "api-reference/server-api/event-handling" + ] + }, + { + "group": "Client APIs", + "pages": [ + "api-reference/client-api/connection-management", + "api-reference/client-api/resource-consumption", + "api-reference/client-api/tool-invocation" + ] + }, + { + "group": "TypeScript SDK", + "pages": [ + "api-reference/typescript/class-reference", + "api-reference/typescript/type-definitions", + "api-reference/typescript/examples" + ] + }, + { + "group": "Python SDK", + "pages": [ + "api-reference/python/class-reference", + "api-reference/python/type-hints", + "api-reference/python/examples" ] } ], diff --git a/quickstart.mdx b/quickstart.mdx index c44cfaa..283553b 100644 --- a/quickstart.mdx +++ b/quickstart.mdx @@ -1,86 +1,305 @@ --- -title: 'Quickstart' -description: 'Start building awesome documentation in under 5 minutes' +title: "Quickstart" +description: "Get started with MCP in less than 5 minutes" --- -## Setup your development +Give Claude superpowers by connecting it to your local computer! This guide will show you how to set up Model Context Protocol (MCP) and experience its magic in just 5 minutes. -Learn how to update your docs locally and deploy them to the public. + +Model Context Protocol (MCP) is like giving Claude hands and eyes on your computer. It can: +- Take screenshots and analyze what's on your screen +- Read and analyze files from your computer +- Help you automate repetitive tasks +- Connect to your databases and local tools -### Edit and preview +And it does all this while maintaining security - Claude can only access what you explicitly allow. + + +## Prerequisites + + +```bash macOS +# Check if you have Node.js installed +node --version # Should be v16 or higher + +# Check if you have git installed +git --version +``` + +```bash Installation +# Install Node.js from https://nodejs.org +# Install git from https://git-scm.com + +# Or use Homebrew +brew install node git +``` + + +## Quick Setup + + + + Let's start by getting some pre-built MCP servers that Claude can use: + + ```bash + # Clone the example servers + git clone https://github.com/modelcontextprotocol/example-servers + cd example-servers + + # Install dependencies and build + npm install + npm run build + + # Make servers available globally + npm install -g + ``` + + + + Open your Claude Desktop App configuration: + + ```bash + code ~/Library/Application\ Support/Claude/claude_desktop_config.json + ``` + + Add this configuration (replace YOUR_USERNAME with your actual username): + + ```json + { + "mcpServers": { + "osascript": { + "command": "mcp-server-osascript", + "env": { + "HOME": "/Users/YOUR_USERNAME" + } + } + } + } + ``` + + Save and **restart Claude Desktop App**. + + + + When you first use screen capture features, macOS will ask for permissions: + + + Screenshot permissions dialog + + + Grant these permissions to Claude Desktop App: + - Screen Recording (for screenshots) + - Automation (for window management) + + + +## Try It Out! ๐ŸŽ‰ + +Now for the fun part! Try these examples to see MCP in action: - - During the onboarding process, we created a repository on your Github with - your docs content. You can find this repository on our - [dashboard](https://dashboard.mintlify.com). To clone the repository - locally, follow these - [instructions](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository) - in your terminal. + + Ask Claude: + ``` + Can you take a screenshot of my desktop and describe what you see? + ``` + + Claude will: + 1. Use MCP to capture your screen + 2. Add it as context to your conversation + 3. Analyze and describe what it sees + + Try follow-up questions like: + - "How many windows do I have open?" + - "What apps am I running?" + - "Is my battery level low?" - - Previewing helps you make sure your changes look as intended. We built a - command line interface to render these changes locally. 1. Install the - [Mintlify CLI](https://www.npmjs.com/package/mintlify) to preview the - documentation changes locally with this command: ``` npm i -g mintlify ``` - 2. Run the following command at the root of your documentation (where - `mint.json` is): ``` mintlify dev ``` + + + Ask Claude: + ``` + I have several windows open and it's messy. Could you help me organize them? Maybe arrange my browser windows side by side? + ``` + + Claude will: + 1. Take a screenshot to assess the situation + 2. Use AppleScript to organize your windows + 3. Take another screenshot to confirm the changes + + Pro tip: You can ask Claude to create specific layouts or focus on particular apps! + + + + Ask Claude: + ``` + I often need to arrange my windows with: + - Browser on the left half + - VS Code on the top right quarter + - Terminal on the bottom right quarter + + Can you create an AppleScript to automate this layout? + ``` + + Claude will create a reusable script that you can save and run anytime! -### Deploy your changes +## What Just Happened? - + +Let's break down the magic: - - Our Github app automatically deploys your changes to your docs site, so you - don't need to manage deployments yourself. You can find the link to install on - your [dashboard](https://dashboard.mintlify.com). Once the bot has been - successfully installed, there should be a check mark next to the commit hash - of the repo. - - - [Commit and push your changes to - Git](https://docs.github.com/en/get-started/using-git/pushing-commits-to-a-remote-repository#about-git-push) - for your changes to update in your docs site. If you push and don't see that - the Github app successfully deployed your changes, you can also manually - update your docs through our [dashboard](https://dashboard.mintlify.com). - +1. When you installed the `osascript` server, you gave Claude a way to: + - Take screenshots (see what you see) + - Run AppleScript (control your windows) + - Automate macOS tasks - +2. The MCP protocol lets Claude: + - Request these actions securely + - Get results back in real-time + - Chain actions together intelligently -## Update your docs - -Add content directly in your files with MDX syntax and React components. You can use any of our components, or even build your own. - - - - - Add flair to your docs with personalized branding. +3. All of this happens locally on your machine - no data leaves your computer! - - Implement your OpenAPI spec and enable API user interaction. - +## Add More Capabilities - - Draw insights from user interactions with your documentation. - - - - Keep your docs on your own website's subdomain. - +Want to give Claude even more superpowers? Add these servers to your configuration: + + + Add this to your config to let Claude read and analyze files: + ```json + "tee": { + "command": "mcp-server-tee", + "args": ["tail", "-f", "/var/log/system.log"], + "env": { + "HOME": "/Users/YOUR_USERNAME" + } + } + ``` + + + + Connect Claude to your PostgreSQL database: + ```json + "postgres": { + "command": "mcp-server-postgres", + "args": ["postgresql://localhost/mydb"], + "env": { + "HOME": "/Users/YOUR_USERNAME" + } + } + ``` + + + + Enable web automation capabilities: + ```json + "puppeteer": { + "command": "mcp-server-puppeteer", + "env": { + "HOME": "/Users/YOUR_USERNAME" + } + } + ``` + + +## Quick Troubleshooting + + + + 1. Check if MCP is enabled: + - Click the ๐Ÿ”Œ icon in Claude + - You should see your configured servers + + 2. Verify your config: + ```bash + cat ~/Library/Application\ Support/Claude/claude_desktop_config.json + ``` + + 3. Restart Claude completely: + - Quit the app (not just close the window) + - Start it again + + + + Run this command to see Claude's logs: + ```bash + tail -f ~/Claude.log + ``` + + Common fixes: + - Check `HOME` env variable in your config + - Grant missing permissions in System Settings + - Try running example commands manually in Terminal + + + +## Pro Tips + + + + During development: + - Use Command+R to reload Claude + - This restarts MCP servers without closing Claude + - Perfect for testing config changes! + + + + Run multiple servers for maximum capability: + ```json + { + "mcpServers": { + "osascript": { ... }, + "postgres": { ... }, + "puppeteer": { ... }, + "tee": { ... } + } + } + ``` + + Now Claude can: + - Take screenshots + - Query your database + - Automate web tasks + - Read local files + + All in the same conversation! + + + + Add `"debug": true` to see what's happening: + ```json + { + "mcpServers": { + "osascript": { + "command": "mcp-server-osascript", + "env": { ... }, + "debug": true + } + } + } + ``` + + Then watch the logs: + ```bash + tail -f ~/Claude.log + ``` + + + +## Next Steps + + +Now that you've experienced MCP, you might want to: + +1. [Build your own MCP server](/mcp-dev) - Create custom integrations +2. [Explore example servers](https://github.com/modelcontextprotocol/example-servers) - See what's possible +3. Join our [community](/community) - Share your MCP creations! + + + +Remember: Claude will help you write MCP servers! Just describe what you want to build, and Claude can guide you through the process. + \ No newline at end of file diff --git a/your-first-server.mdx b/your-first-server.mdx new file mode 100644 index 0000000..c17200d --- /dev/null +++ b/your-first-server.mdx @@ -0,0 +1,319 @@ +--- +title: "Your first MCP server" +description: "Get started with MCP by building a weather app in 5 minutes" +--- + +Connect AI to anything. MCP (Model Context Protocol) lets your AI applications seamlessly interact with data sources, tools, and services. + + + **Real-world example:** In this quickstart, we'll build an AI-powered weather app that lets users ask about current conditions in any city. Our app will use MCP to connect to a weather API. + + +![Weather App Demo](weather-app-demo.gif) + +## Installation + + + + ```bash + pip install mcp-sdk # Using pip + uv add mcp-sdk # Using uv (recommended) + ``` + + **Requirements:** + - Python 3.8 or higher + - pip or uv package manager + + + ```bash + npm install @modelcontextprotocol/sdk + ``` + + **Requirements:** + - Node.js 16 or higher + - TypeScript 4.7 or higher + - npm or yarn package manager + + + +## Step 1: Create an MCP Server + +Our server will expose a tool that the AI can use to fetch the current weather for any city. + + + + ```python weather_server.py + from mcp.server import Server + from mcp.server.stdio import stdio_server + import aiohttp + + server = Server("weather-server") + + @server.list_tools() + async def list_tools(): + return [{ + "name": "get_weather", + "description": "Get current weather for a city", + "inputSchema": { + "type": "object", + "properties": { + "city": {"type": "string"} + } + } + }] + + @server.call_tool() + async def call_tool(name: str, args: dict): + if name == "get_weather": + async with aiohttp.ClientSession() as session: + city = args["city"] + url = f"https://api.openweathermap.org/data/2.5/weather?q={city}&appid=YOUR_API_KEY" + async with session.get(url) as resp: + data = await resp.json() + return data["weather"][0]["description"] + + async def main(): + async with stdio_server() as (read, write): + await server.run(read, write) + + if __name__ == "__main__": + import asyncio + asyncio.run(main()) + ``` + + To make real API requests, sign up for a free API key at [OpenWeatherMap](https://openweathermap.org). + + + + ```typescript weather_server.ts + import { Server } from "@modelcontextprotocol/sdk/server"; + import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio"; + import axios from "axios"; + + const server = new Server({ + name: "weather-server", + version: "1.0.0", + }); + + server.setRequestHandler(ListToolsRequestSchema, async () => { + return { + tools: [{ + name: "get_weather", + description: "Get current weather for a city", + inputSchema: { + type: "object", + properties: { + city: { type: "string" } + } + } + }] + }; + }); + + server.setRequestHandler(CallToolRequestSchema, async (request) => { + if (request.params.name === "get_weather") { + const city = request.params.arguments?.city as string; + const url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=YOUR_API_KEY`; + const resp = await axios.get(url); + return { + toolResult: resp.data.weather[0].description + }; + } + throw new Error("Tool not found"); + }); + + async function main() { + const transport = new StdioServerTransport(); + await server.connect(transport); + } + + main().catch(console.error); + ``` + + To make real API requests, sign up for a free API key at [OpenWeatherMap](https://openweathermap.org). + + + +## Step 2: Integrate the Server into Your AI App + + + This example uses a mock AI model. In a real app, you would replace this with your actual AI model code that generates a response based on the user's message and any MCP context. + + + + + ```python app.py + from mcp.client import ClientSession + from mcp.client.stdio import stdio_client + import re + + def extract_city(message): + match = re.search(r"in\s+(\w+)", message) + if match: + return match.group(1) + else: + return None + + async def get_weather(city): + async with stdio_client(command="python weather_server.py") as (read, write): + async with ClientSession(read, write) as session: + await session.initialize() + return await session.call_tool("get_weather", {"city": city}) + + async def handle_message(message): + city = extract_city(message) + if city: + weather = await get_weather(city) + return f"The current weather in {city} is: {weather}" + else: + return generate_response(message) # Your existing AI logic + + async def main(): + while True: + message = input("> ") + response = await handle_message(message) + print(response) + + if __name__ == "__main__": + import asyncio + asyncio.run(main()) + ``` + + + + ```typescript app.ts + import { Client } from "@modelcontextprotocol/sdk/client"; + import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio"; + import { CallToolResultSchema } from "@modelcontextprotocol/sdk/types"; + import readline from "readline"; + + function extractCity(message: string): string | null { + const match = message.match(/in\s+(\w+)/); + if (match) { + return match[1]; + } else { + return null; + } + } + + async function getWeather(city: string): Promise { + const transport = new StdioClientTransport({ + command: "ts-node weather_server.ts", + }); + const client = new Client({ + name: "weather-app", + version: "1.0.0", + }); + await client.connect(transport); + const result = await client.request( + { + method: "tools/call", + params: { + name: "get_weather", + arguments: { city } + } + }, + CallToolResultSchema + ); + return result.toolResult as string; + } + + async function handleMessage(message: string): Promise { + const city = extractCity(message); + if (city) { + const weather = await getWeather(city); + return `The current weather in ${city} is: ${weather}`; + } else { + return generateResponse(message); // Your existing AI logic + } + } + + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout + }); + + rl.prompt(); + rl.on("line", async (line) => { + const response = await handleMessage(line); + console.log(response); + rl.prompt(); + }); + ``` + + + +## Step 3: Run It! + + + + In one terminal, start the server: + ```bash + python weather_server.py + ``` + In another terminal, start the app: + ```bash + python app.py + ``` + + + In one terminal, start the server: + ```bash + ts-node weather_server.ts + ``` + In another terminal, start the app: + ```bash + ts-node app.ts + ``` + + + +Now chat with your AI assistant! Try asking about the weather in various cities. + +``` +> What's the weather like in Tokyo? +The current weather in Tokyo is: few clouds + +> How about London? +The current weather in London is: scattered clouds +``` + +## Why MCP Rocks + +- **Effortless integrations.** No custom code needed to connect AI to any API, database, or service. +- **Async built-in.** MCP client/server communication is fully asynchronous out of the box. +- **Type-safe.** Requests and responses are validated against strict schemas. + +## Next Steps + + + + Understand resources, tools, prompts and more + + + Databases, APIs, embeddings, vectorstores... + + + Expose your AI through an API or website + + + Ensure your app is rock solid + + + +## Getting Help + + + + Get support and see what others are building + + + Look up library classes and functions + + + Quick answers to common questions + + + Report bugs or suggest improvements + + \ No newline at end of file From e4dd2199fefbf2321e1398ae365ac2064aa67803 Mon Sep 17 00:00:00 2001 From: Zack Lee Date: Mon, 18 Nov 2024 08:48:20 -0500 Subject: [PATCH 2/6] finished draft of quickstarts --- .DS_Store | Bin 6148 -> 8196 bytes docs/deployment/configuration.mdx | 5 - docs/deployment/environment-setup.mdx | 4 - docs/deployment/monitoring.mdx | 8 - docs/development.mdx | 0 docs/guides/claude.mdx | 235 +++++++ docs/guides/first-mcp-server.mdx | 8 - docs/guides/first-server-python.mdx | 422 ++++++++++++ docs/guides/first-server-ts.mdx | 533 +++++++++++++++ docs/guides/implementing-tools.mdx | 8 - docs/guides/integrate-python.mdx | 442 ++++++++++++ docs/guides/integrate-ts.mdx | 885 +++++++++++++++++++++++++ docs/guides/testing-debugging.mdx | 8 - docs/guides/working-with-resources.mdx | 8 - docs/installation.mdx | 160 ----- docs/recipes/api-integration.mdx | 8 - docs/recipes/database-integration.mdx | 8 - docs/recipes/local-files.mdx | 8 - docs/recipes/realtime-updates.mdx | 8 - introduction.mdx | 161 +++-- logo/dark.svg | 66 +- logo/light.svg | 56 +- mint.json | 42 +- quickstart.mdx | 305 --------- 24 files changed, 2667 insertions(+), 721 deletions(-) delete mode 100644 docs/deployment/configuration.mdx delete mode 100644 docs/deployment/environment-setup.mdx delete mode 100644 docs/deployment/monitoring.mdx delete mode 100644 docs/development.mdx create mode 100644 docs/guides/claude.mdx delete mode 100644 docs/guides/first-mcp-server.mdx create mode 100644 docs/guides/first-server-python.mdx create mode 100644 docs/guides/first-server-ts.mdx delete mode 100644 docs/guides/implementing-tools.mdx create mode 100644 docs/guides/integrate-python.mdx create mode 100644 docs/guides/integrate-ts.mdx delete mode 100644 docs/guides/testing-debugging.mdx delete mode 100644 docs/guides/working-with-resources.mdx delete mode 100644 docs/installation.mdx delete mode 100644 docs/recipes/api-integration.mdx delete mode 100644 docs/recipes/database-integration.mdx delete mode 100644 docs/recipes/local-files.mdx delete mode 100644 docs/recipes/realtime-updates.mdx delete mode 100644 quickstart.mdx diff --git a/.DS_Store b/.DS_Store index a123578f911e8d1eab8bfaea4ddf9c04be790c6f..c2cd63df2ba7efc55f73110e36efb638b6dcb733 100644 GIT binary patch delta 351 zcmZ8dy-or_7@W<1(M3)X0>p-h55PrVfQX3&g|V=-FbAAya=BFwttn_NF54O#A7NX2 z<9qlHmO5*qL3cCX|IU7y<^J+;2Y@=dn;ZZkG(_;*)$+Do#(S+s=radqNO4Kf`?_h1 z@0thwylzankn=FMi3B&eMsIZ#ImSqbnH`TZI||IifQUc84yLc>uSMzOkv%NytaO``?Fb| v*?dZ3g8r8y2VQHl@kYR#cLjf|mEK|%P7=uv+GcGXI9 delta 132 zcmZp1XfcprU|?W$DortDU=RQ@Ie-{Mvv5r;6q~50D9Qtp2aDw}D)Bpqm+(5z=WYEUK@640=WjsN~GB81` N0NKj0Ii6<@GXU8D7J~o) diff --git a/docs/deployment/configuration.mdx b/docs/deployment/configuration.mdx deleted file mode 100644 index 91b7311..0000000 --- a/docs/deployment/configuration.mdx +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "Configuration" -description: "Configure MCP servers for production" ---- - diff --git a/docs/deployment/environment-setup.mdx b/docs/deployment/environment-setup.mdx deleted file mode 100644 index 102a91f..0000000 --- a/docs/deployment/environment-setup.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: "Environment Setup" -description: "Set up your production environment" ---- \ No newline at end of file diff --git a/docs/deployment/monitoring.mdx b/docs/deployment/monitoring.mdx deleted file mode 100644 index 72aa561..0000000 --- a/docs/deployment/monitoring.mdx +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: "Monitoring" -description: "Monitor your MCP servers in production" ---- - -# Monitoring - -Monitor your MCP servers in production diff --git a/docs/development.mdx b/docs/development.mdx deleted file mode 100644 index e69de29..0000000 diff --git a/docs/guides/claude.mdx b/docs/guides/claude.mdx new file mode 100644 index 0000000..8c862f0 --- /dev/null +++ b/docs/guides/claude.mdx @@ -0,0 +1,235 @@ +--- +title: "Connecting MCP to Claude" +description: "Get started with MCP in less than 5 minutes" +--- + +Give Claude superpowers by connecting it to your local computer! This guide will show you how to set up Model Context Protocol (MCP) and experience its magic in just 5 minutes. + + +MCP connects Claude to external data sources and tools. In this guide, we'll give Claude the ability to: +- Take screenshots and analyze them +- Control window arrangement +- Execute local automation scripts + +And it does this all securely - Claude can only access what you explicitly allow through MCP servers. + + +## Prerequisites + +- macOS (Windows/Linux guides coming soon) +- Node.js v16 or higher (`node --version` to check) +- Git (`git --version` to check) +- [Claude desktop app](https://claude.ai/download) installed + + +```bash +# Using Homebrew +brew install node git + +# Or download directly: +# Node.js: https://nodejs.org +# Git: https://git-scm.com +``` + + +## Installation + + + + Let's start by getting some pre-built MCP servers that Claude can use: + + ```bash + # Clone the example servers + git clone https://github.com/modelcontextprotocol/example-servers + cd example-servers + + # Install dependencies and build + npm install + npm run build + + # Make servers available globally + npm install -g + ``` + + + + Open your Claude Desktop App configuration: + + ```bash + code ~/Library/Application\ Support/Claude/claude_desktop_config.json + ``` + + Add this configuration (replace YOUR_USERNAME with your actual username): + + ```json + { + "mcpServers": { + "osascript": { + "command": "mcp-server-osascript", + } + } + } + ``` + + Save and **restart Claude Desktop App**. + + + +## Test it out + +Let's verify everything is working with a simple example. Try sending this prompt to Claude: + +``` +Can you take a screenshot of my desktop and describe what you see? +``` + +Claude will: + +1. Request permission to take a screenshot +2. Capture your screen through the MCP server +3. Analyze and describe the screenshot + + + Example Claude conversation showing a screenshot analysis + + +The first time you use screenshot features, macOS will ask for permissions: +- Screen Recording (for screenshots) +- Automation (for window control) +You'll need to grant these to Claude.app in System Settings. + + +## Try these examples + +Now that MCP is working, try these increasingly powerful examples: + + + + ``` + Could you analyze my open windows and tell me: + - How many windows I have open + - Which apps are running + - If any windows look cluttered + ``` + + + ``` + Could you help organize my windows? I'd like: + - Browser on the left half + - VSCode on the right half + ``` + + + ``` + I often need this window layout for coding: + - VSCode taking up the left 60% + - Terminal in the top right + - Browser in the bottom right + Could you create an AppleScript to automate this? + ``` + + + +## What just happened? + +Let's break down the magic: + +1. When you installed the `osascript` server, you gave Claude a way to: + - Take screenshots (see what you see) + - Run AppleScript (control your windows) + - Automate macOS tasks + +2. The MCP protocol lets Claude: + - Request these actions securely + - Get results back in real-time + - Chain actions together intelligently + +3. All of this happens locally on your machine - no data leaves your computer! + +## Add more capabilities + +Want to give Claude even more superpowers? Add these servers to your configuration: + + + Add this to your config to let Claude read and analyze files: + ```json + "tee": { + "command": "mcp-server-tee", + "args": ["tail", "-f", "/var/log/system.log"], + "env": { + "HOME": "/Users/YOUR_USERNAME" + } + } + ``` + + + + Connect Claude to your PostgreSQL database: + ```json + "postgres": { + "command": "mcp-server-postgres", + "args": ["postgresql://localhost/mydb"], + "env": { + "HOME": "/Users/YOUR_USERNAME" + } + } + ``` + + + + Enable web automation capabilities: + ```json + "puppeteer": { + "command": "mcp-server-puppeteer", + } + ``` + + + +## Troubleshooting + + + + 1. Check if MCP is enabled: + - Click the ๐Ÿ”Œ icon in Claude + - You should see your configured servers + + 2. Verify your config: + ```bash + cat ~/Library/Application\ Support/Claude/claude_desktop_config.json + ``` + + 3. Restart Claude completely: + - Quit the app (not just close the window) + - Start it again + + + + Run this command to see Claude's logs: + ```bash + tail -f ~/Claude.log + ``` + + Common fixes: + - Check `HOME` env variable in your config + - Grant missing permissions in System Settings + - Try running example commands manually in Terminal + + + +## Next Steps + + + + Create your own MCP integrations to give Claude new capabilities. + + + + Browse our collection of example servers to see what's possible. + + + + Share your MCP creations and connect with other developers. + [Join us โ†’](/community) + + diff --git a/docs/guides/first-mcp-server.mdx b/docs/guides/first-mcp-server.mdx deleted file mode 100644 index f2df732..0000000 --- a/docs/guides/first-mcp-server.mdx +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: "Your First MCP Server" -description: "Build a complete MCP server from scratch" ---- - -# Your First MCP Server - -Build a complete MCP server from scratch diff --git a/docs/guides/first-server-python.mdx b/docs/guides/first-server-python.mdx new file mode 100644 index 0000000..da5be94 --- /dev/null +++ b/docs/guides/first-server-python.mdx @@ -0,0 +1,422 @@ +--- +title: "Your First MCP Server (Python)" +description: "Create a simple MCP server in Python in 15 minutes" +--- + +Let's build your first MCP server in Python! We'll create a weather server that provides current weather data as a resource and lets Claude fetch forecasts using tools. + + +This guide uses the OpenWeatherMap API. You'll need a free API key from [OpenWeatherMap](https://openweathermap.org/api) to follow along. + + +## Prerequisites + + + + You'll need Python 3.8 or higher: + + ```bash + python3 --version # Should be 3.8 or higher + ``` + + + + ```bash + # Create and activate virtual environment + python3 -m venv mcp-weather + cd mcp-weather + source bin/activate # On Windows: .\Scripts\activate + ``` + + + + ```bash + pip install modelcontextprotocol-sdk requests + ``` + + + + 1. Sign up at [OpenWeatherMap](https://openweathermap.org/api) + 2. Copy your API key + 3. Set it as an environment variable: + ```bash + export OPENWEATHER_API_KEY='your-api-key' + ``` + + + +## Create Your Server + + + + ```bash + mkdir weather_server + cd weather_server + touch weather_server.py + ``` + + + + Open `weather_server.py` and add this starter code: + + ```python + from modelcontextprotocol.server import Server + from modelcontextprotocol.server.stdio import StdioServerTransport + from modelcontextprotocol.types import ( + ListResourcesRequestSchema, + ListToolsRequestSchema, + ReadResourceRequestSchema, + CallToolRequestSchema + ) + import os + import requests + import json + from datetime import datetime + + API_KEY = os.getenv('OPENWEATHER_API_KEY') + BASE_URL = 'http://api.openweathermap.org/data/2.5' + + class WeatherServer: + def __init__(self): + self.server = Server( + name="example-weather-server", + version="0.1.0" + ) + self.default_city = "San Francisco" + self.setup_handlers() + + def setup_handlers(self): + # We'll add handlers here + pass + + async def run(self): + transport = StdioServerTransport() + await self.server.connect(transport) + + if __name__ == "__main__": + import asyncio + server = WeatherServer() + asyncio.run(server.run()) + ``` + + + + Let's add handlers to expose current weather as a resource: + + ```python + def setup_handlers(self): + self.server.set_request_handler( + ListResourcesRequestSchema, + self.handle_list_resources + ) + self.server.set_request_handler( + ReadResourceRequestSchema, + self.handle_read_resource + ) + + async def handle_list_resources(self, request): + return { + "resources": [{ + "uri": f"weather://{self.default_city}/current", + "name": f"Current weather in {self.default_city}", + "mimeType": "application/json" + }] + } + + async def handle_read_resource(self, request): + city = self.default_city + if request.params.uri != f"weather://{city}/current": + raise ValueError(f"Unknown resource: {request.params.uri}") + + response = requests.get( + f"{BASE_URL}/weather", + params={ + "q": city, + "appid": API_KEY, + "units": "metric" + } + ) + data = response.json() + + return { + "contents": [{ + "uri": request.params.uri, + "mimeType": "application/json", + "text": json.dumps({ + "temperature": data["main"]["temp"], + "conditions": data["weather"][0]["description"], + "humidity": data["main"]["humidity"], + "wind_speed": data["wind"]["speed"], + "timestamp": datetime.now().isoformat() + }, indent=2) + }] + } + ``` + + + + Now let's add a tool to fetch weather forecasts: + + ```python + def setup_handlers(self): + # Add these lines to the existing method + self.server.set_request_handler( + ListToolsRequestSchema, + self.handle_list_tools + ) + self.server.set_request_handler( + CallToolRequestSchema, + self.handle_call_tool + ) + + async def handle_list_tools(self, request): + return { + "tools": [{ + "name": "get_forecast", + "description": "Get weather forecast for a city", + "inputSchema": { + "type": "object", + "properties": { + "city": { + "type": "string", + "description": "City name" + }, + "days": { + "type": "number", + "description": "Number of days (1-5)" + } + }, + "required": ["city"] + } + }] + } + + async def handle_call_tool(self, request): + if request.params.name != "get_forecast": + raise ValueError(f"Unknown tool: {request.params.name}") + + args = request.params.arguments + city = args.get("city", self.default_city) + days = min(int(args.get("days", 3)), 5) + + response = requests.get( + f"{BASE_URL}/forecast", + params={ + "q": city, + "appid": API_KEY, + "units": "metric", + "cnt": days * 8 # API returns 3-hour intervals + } + ) + data = response.json() + + # Process and return daily forecasts + forecasts = [] + for i in range(0, len(data["list"]), 8): # One day = 8 intervals + day_data = data["list"][i] + forecasts.append({ + "date": day_data["dt_txt"].split()[0], + "temperature": day_data["main"]["temp"], + "conditions": day_data["weather"][0]["description"] + }) + + return {"toolResult": forecasts} + ``` + + + + 1. Save all changes + 2. Run your server: + ```bash + python weather_server.py + ``` + + + +## Connect to Claude + + + + ```bash + # From your project directory + pip install -e . + ``` + + + + Add this to your `claude_desktop_config.json`: + + ```json + { + "mcpServers": { + "weather": { + "command": "python", + "args": ["-m", "weather_server"], + "env": { + "OPENWEATHER_API_KEY": "your-api-key", + "HOME": "/Users/YOUR_USERNAME" + } + } + } + } + ``` + + + + 1. Quit Claude completely + 2. Start Claude again + 3. Verify your weather server appears in the ๐Ÿ”Œ menu + + + +## Try It Out! + + + + Ask Claude: + ``` + What's the current weather in San Francisco? Can you analyze the conditions? + ``` + + Claude will: + 1. Access the weather resource + 2. Parse the JSON data + 3. Provide a natural language summary + + + + Ask Claude: + ``` + Can you get me a 5-day forecast for Tokyo and tell me if I should pack an umbrella? + ``` + + Claude will: + 1. Use the `get_forecast` tool + 2. Analyze the forecast data + 3. Give you packing advice + + + +## Understanding the Code + +Let's break down the key MCP concepts used in this server: + + + + ```python + async def handle_list_resources(self, request): + return { + "resources": [{ + "uri": f"weather://{self.default_city}/current", + "name": f"Current weather in {self.default_city}", + "mimeType": "application/json" + }] + } + ``` + Resources provide data that Claude can access as context. In this case, we're exposing current weather data that Claude can read and analyze. + + + + ```python + async def handle_list_tools(self, request): + return { + "tools": [{ + "name": "get_forecast", + "description": "Get weather forecast for a city", + "inputSchema": { + "type": "object", + "properties": { + "city": {"type": "string"}, + "days": {"type": "number"} + } + } + }] + } + ``` + Tools let Claude take actions through your server. The `inputSchema` defines what parameters Claude can provide. + + + + ```python + async def run(self): + transport = StdioServerTransport() + await self.server.connect(transport) + ``` + The transport layer handles communication between Claude and your server. Here we're using stdio, but MCP also supports WebSocket and SSE. + + + +## Next Steps + +Now that you've built your first MCP server, try these enhancements: + + + + - Air quality data + - Weather alerts + - Historical weather + + + + - Compare multiple cities + - Get detailed hourly forecasts + - Save favorite locations + + + + - Handle API errors gracefully + - Add input validation + - Rate limiting + + + + - Weather alerts + - Temperature changes + - Condition updates + + + +## Troubleshooting + + + + ```bash + pip install modelcontextprotocol-sdk --upgrade + ``` + Ensure you're using the latest SDK version. + + + + 1. Verify your API key is set: + ```bash + echo $OPENWEATHER_API_KEY + ``` + 2. Check the API response for error messages + 3. Ensure you're within free tier limits + + + + 1. Check Claude's logs: + ```bash + tail -f ~/Claude.log + ``` + 2. Verify your config JSON syntax + 3. Ensure Python path is correct in config + + + + +Remember: This is just the beginning! MCP servers can provide any type of data or functionality to Claude. Think about what unique capabilities you could add to Claude through MCP. + \ No newline at end of file diff --git a/docs/guides/first-server-ts.mdx b/docs/guides/first-server-ts.mdx new file mode 100644 index 0000000..c94021f --- /dev/null +++ b/docs/guides/first-server-ts.mdx @@ -0,0 +1,533 @@ +--- +title: "Your First MCP Server (TypeScript)" +description: "Create a simple MCP server in TypeScript in 15 minutes" +--- + +Let's build your first MCP server in TypeScript! We'll create a weather server that provides current weather data as a resource and lets Claude fetch forecasts using tools. + + +This guide uses the OpenWeatherMap API. You'll need a free API key from [OpenWeatherMap](https://openweathermap.org/api) to follow along. + + +## Prerequisites + + + + You'll need Node.js 16 or higher: + + ```bash + node --version # Should be v16 or higher + npm --version + ``` + + + + ```bash + mkdir weather-server + cd weather-server + npm init -y + ``` + + + + ```bash + npm install @modelcontextprotocol/sdk axios dotenv typescript @types/node + npm install --save-dev ts-node + ``` + + + + Create `tsconfig.json`: + ```json + { + "compilerOptions": { + "target": "ES2020", + "module": "ES2020", + "moduleResolution": "node", + "esModuleInterop": true, + "outDir": "./dist", + "rootDir": "./src", + "strict": true + }, + "include": ["src/**/*"] + } + ``` + + + + Create `.env`: + ```bash + OPENWEATHER_API_KEY=your-api-key-here + ``` + + + +## Create Your Server + + + + ```bash + mkdir src + touch src/index.ts + touch src/types.ts + ``` + + + + In `src/types.ts`: + + ```typescript + export interface WeatherData { + temperature: number; + conditions: string; + humidity: number; + wind_speed: number; + timestamp: string; + } + + export interface ForecastDay { + date: string; + temperature: number; + conditions: string; + } + + export interface GetForecastArgs { + city: string; + days?: number; + } + ``` + + + + In `src/index.ts`: + + ```typescript + import { Server } from "@modelcontextprotocol/sdk/server/index.js"; + import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; + import axios from "axios"; + import dotenv from "dotenv"; + import { WeatherData, ForecastDay, GetForecastArgs } from "./types.js"; + + dotenv.config(); + + const API_KEY = process.env.OPENWEATHER_API_KEY; + const BASE_URL = 'http://api.openweathermap.org/data/2.5'; + const DEFAULT_CITY = 'San Francisco'; + + class WeatherServer { + private server: Server; + + constructor() { + this.server = new Server({ + name: "example-weather-server", + version: "0.1.0" + }); + this.setupHandlers(); + } + + private setupHandlers(): void { + // We'll add handlers here + } + + async run(): Promise { + const transport = new StdioServerTransport(); + await this.server.connect(transport); + } + } + + const server = new WeatherServer(); + server.run().catch(console.error); + ``` + + + + Add this to the `setupHandlers` method: + + ```typescript + private setupHandlers(): void { + this.server.setRequestHandler( + ListResourcesRequestSchema, + async () => ({ + resources: [{ + uri: `weather://${DEFAULT_CITY}/current`, + name: `Current weather in ${DEFAULT_CITY}`, + mimeType: "application/json" + }] + }) + ); + + this.server.setRequestHandler( + ReadResourceRequestSchema, + async (request) => { + const city = DEFAULT_CITY; + if (request.params.uri !== `weather://${city}/current`) { + throw new Error(`Unknown resource: ${request.params.uri}`); + } + + const response = await axios.get(`${BASE_URL}/weather`, { + params: { + q: city, + appid: API_KEY, + units: "metric" + } + }); + + const weatherData: WeatherData = { + temperature: response.data.main.temp, + conditions: response.data.weather[0].description, + humidity: response.data.main.humidity, + wind_speed: response.data.wind.speed, + timestamp: new Date().toISOString() + }; + + return { + contents: [{ + uri: request.params.uri, + mimeType: "application/json", + text: JSON.stringify(weatherData, null, 2) + }] + }; + } + ); + } + ``` + + + + Add these handlers to the `setupHandlers` method: + + ```typescript + this.server.setRequestHandler( + ListToolsRequestSchema, + async () => ({ + tools: [{ + name: "get_forecast", + description: "Get weather forecast for a city", + inputSchema: { + type: "object", + properties: { + city: { + type: "string", + description: "City name" + }, + days: { + type: "number", + description: "Number of days (1-5)" + } + }, + required: ["city"] + } + }] + }) + ); + + this.server.setRequestHandler( + CallToolRequestSchema, + async (request) => { + if (request.params.name !== "get_forecast") { + throw new Error(`Unknown tool: ${request.params.name}`); + } + + const args = request.params.arguments as GetForecastArgs; + const city = args.city || DEFAULT_CITY; + const days = Math.min(args.days || 3, 5); + + const response = await axios.get(`${BASE_URL}/forecast`, { + params: { + q: city, + appid: API_KEY, + units: "metric", + cnt: days * 8 // API returns 3-hour intervals + } + }); + + const forecasts: ForecastDay[] = []; + for (let i = 0; i < response.data.list.length; i += 8) { + const dayData = response.data.list[i]; + forecasts.push({ + date: dayData.dt_txt.split(' ')[0], + temperature: dayData.main.temp, + conditions: dayData.weather[0].description + }); + } + + return { toolResult: forecasts }; + } + ); + ``` + + + + Add these scripts to `package.json`: + ```json + { + "scripts": { + "build": "tsc", + "start": "node dist/index.js", + "dev": "ts-node src/index.ts" + } + } + ``` + + Then run: + ```bash + npm run build + npm start + ``` + + + +## Connect to Claude + + + + ```bash + npm install -g + ``` + + + + Add to `claude_desktop_config.json`: + + ```json + { + "mcpServers": { + "weather": { + "command": "weather-server", + "env": { + "OPENWEATHER_API_KEY": "your-api-key", + "HOME": "/Users/YOUR_USERNAME" + } + } + } + } + ``` + + + + 1. Quit Claude completely + 2. Start Claude again + 3. Look for your weather server in the ๐Ÿ”Œ menu + + + +## Try It Out! + + + + Ask Claude: + ``` + What's the current weather in San Francisco? Can you analyze the conditions? + ``` + + + + Ask Claude: + ``` + Can you get me a 5-day forecast for Tokyo and tell me if I should pack an umbrella? + ``` + + + + Ask Claude: + ``` + Can you analyze the forecast for both Tokyo and San Francisco and tell me which city will be warmer this week? + ``` + + + +## Understanding the Code + + + + ```typescript + interface WeatherData { + temperature: number; + conditions: string; + humidity: number; + wind_speed: number; + timestamp: string; + } + ``` + TypeScript adds type safety to our MCP server, making it more reliable and easier to maintain. + + + + ```typescript + this.server.setRequestHandler( + ListResourcesRequestSchema, + async () => ({ + resources: [{ + uri: `weather://${DEFAULT_CITY}/current`, + name: `Current weather in ${DEFAULT_CITY}`, + mimeType: "application/json" + }] + }) + ); + ``` + Resources provide data that Claude can access as context. + + + + ```typescript + { + name: "get_forecast", + description: "Get weather forecast for a city", + inputSchema: { + type: "object", + properties: { + city: { type: "string" }, + days: { type: "number" } + } + } + } + ``` + Tools let Claude take actions through your server with type-safe inputs. + + + +## Best Practices + + + + ```typescript + try { + const response = await axios.get(url); + } catch (error) { + if (axios.isAxiosError(error)) { + throw new Error(`API error: ${error.response?.data.message}`); + } + throw error; + } + ``` + + + + ```typescript + function isValidForecastArgs(args: unknown): args is GetForecastArgs { + return typeof args === "object" && args !== null && + "city" in args; + } + ``` + + + + ```typescript + if (!process.env.OPENWEATHER_API_KEY) { + throw new Error("OPENWEATHER_API_KEY is required"); + } + ``` + + + + ```typescript + const API_ENDPOINTS = { + CURRENT: "weather", + FORECAST: "forecast" + } as const; + ``` + + + +## Enhancements + +Try adding these features to your server: + + + + Add dynamic city resources: + ```typescript + uriTemplate: "weather://{city}/current" + ``` + + + + Cache API responses: + ```typescript + import NodeCache from "node-cache" + ``` + + + + Add API rate limiting: + ```typescript + import rateLimit from "axios-rate-limit" + ``` + + + +## Troubleshooting + + + + ```bash + # Check TypeScript version + npx tsc --version + + # Clean and rebuild + rm -rf dist/ + npm run build + ``` + + + + Add better error logging: + ```typescript + server.onerror = (error) => { + console.error("[MCP Error]", error); + }; + ``` + + + + ```bash + # Check types without building + npx tsc --noEmit + ``` + + + +## Next Steps + + + + Switch to real-time updates with WebSocket transport + + + + Add Jest tests for your MCP server + + + + +Need help? Ask Claude! Since it has access to the MCP SDK documentation, it can help you debug issues and suggest improvements to your server. + \ No newline at end of file diff --git a/docs/guides/implementing-tools.mdx b/docs/guides/implementing-tools.mdx deleted file mode 100644 index da25884..0000000 --- a/docs/guides/implementing-tools.mdx +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: "Implementing Tools" -description: "Create tools that LLMs can invoke" ---- - -# Implementing Tools - -Create tools that LLMs can invoke diff --git a/docs/guides/integrate-python.mdx b/docs/guides/integrate-python.mdx new file mode 100644 index 0000000..e84e9de --- /dev/null +++ b/docs/guides/integrate-python.mdx @@ -0,0 +1,442 @@ +--- +title: "Integrate MCP into Your Python App" +description: "Add MCP support to your LLM application in Python" +--- + +Learn how to integrate MCP into your Python LLM application. We'll build a simple web analyzer that uses Claude to analyze websites, enhanced with MCP's web automation capabilities. + + +This guide uses an existing MCP server ([puppeteer](/servers/puppeteer)) rather than building one from scratch. This lets us focus on the integration patterns. + + +## The example app + +We'll build an "AI Web Analyzer" that: +1. Takes a URL from the user +2. Captures the webpage using MCP +3. Has the LLM analyze the page's content, design, and accessibility + + + Screenshot of the Web Analyzer CLI interface + + +## Prerequisites + + + + ```bash + pip install modelcontextprotocol-sdk anthropic click rich + ``` + + + + ```bash + # Install example MCP servers + git clone https://github.com/modelcontextprotocol/example-servers + cd example-servers + npm install + npm run build + npm install -g + ``` + + + + ```bash + # Set your Anthropic API key + export ANTHROPIC_API_KEY='your-key-here' + ``` + + + +## Building the base app + +First, let's create a basic version without MCP: + + + + ```bash + mkdir web-analyzer + cd web-analyzer + touch analyzer.py + ``` + + + + ```python + # analyzer.py + import click + import anthropic + from rich.console import Console + from rich.panel import Panel + from rich import print as rprint + + console = Console() + client = anthropic.Client() + + def analyze_url(url: str) -> str: + messages = [{ + "role": "user", + "content": f"Please analyze this website: {url}\n\n" + f"I'd like to know about:\n" + f"1. Content quality and organization\n" + f"2. Visual design (based on the URL/description)\n" + f"3. Potential improvements" + }] + + response = client.messages.create( + model="claude-3-opus-20240229", + max_tokens=1000, + messages=messages + ) + return response.content[0].text + + @click.command() + @click.argument('url') + def main(url: str): + with console.status("[bold green]Analyzing website..."): + analysis = analyze_url(url) + + rprint(Panel.fit( + analysis, + title="Website Analysis", + border_style="blue" + )) + + if __name__ == '__main__': + main() + ``` + + + + ```bash + python analyzer.py https://example.com + ``` + + + +## Adding MCP support + +Now let's enhance the app with MCP capabilities: + + + + ```python + # At the top of analyzer.py + from modelcontextprotocol.client import Client + from modelcontextprotocol.client.stdio import StdioClientTransport + import asyncio + import json + from typing import Optional + + class MCPWebClient: + def __init__(self): + self.client = Client( + client_info={ + "name": "web-analyzer", + "version": "0.1.0" + } + ) + self.transport = None + + async def connect(self): + self.transport = StdioClientTransport( + server={ + "command": "mcp-server-puppeteer", + } + ) + await self.client.connect(self.transport) + + async def navigate(self, url: str) -> Optional[str]: + try: + result = await self.client.request( + { + "method": "tools/call", + "params": { + "name": "navigate", + "arguments": {"url": url} + } + }, + schema=CallToolResultSchema + ) + return result.get("toolResult") + except Exception as e: + console.print(f"[red]Error navigating to URL: {e}") + return None + + async def get_console_logs(self) -> str: + result = await self.client.request( + { + "method": "resources/read", + "params": {"uri": "console://logs"} + }, + schema=ReadResourceResultSchema + ) + return result["contents"][0]["text"] + + async def close(self): + if self.transport: + await self.client.close() + ``` + + + ```python + async def analyze_url_with_mcp(url: str) -> str: + # Create and connect MCP client + mcp = MCPWebClient() + await mcp.connect() + # Navigate to the URL + await mcp.navigate(url) + + # Get console logs (includes errors, warnings, etc.) + console_logs = await mcp.get_console_logs() + + # Close the connection + await mcp.close() + + # Analyze with Claude + messages = [{ + "role": "user", + "content": ( + f"Please analyze this website: {url}\n\n" + f"Here are the browser console logs:\n{console_logs}\n\n" + f"Please analyze:\n" + f"1. Content quality and organization\n" + f"2. Visual design\n" + f"3. Technical issues (based on console logs)\n" + f"4. Potential improvements" + ) + }] + + response = client.messages.create( + model="claude-3-opus-20240229", + max_tokens=1000, + messages=messages + ) + return response.content[0].text + + @click.command() + @click.argument('url') + def main(url: str): + with console.status("[bold green]Analyzing website..."): + analysis = asyncio.run(analyze_url_with_mcp(url)) + + rprint(Panel.fit( + analysis, + title="Website Analysis", + border_style="blue" + )) + ``` + + + ```bash + python analyzer.py https://example.com + ``` + + + +## Understanding MCP integration + +Let's break down the key components of MCP integration: + + + ```python + class MCPWebClient: + def __init__(self): + self.client = Client( + client_info={ + "name": "web-analyzer", + "version": "0.1.0" + } + ) + ``` + The MCP client identifies your application and manages the connection to MCP servers. + + + ```python + self.transport = StdioClientTransport( + server={ + "command": "mcp-server-puppeteer", + } + ) + ``` + The transport layer handles communication with the MCP server. Here we're using stdio to talk to the puppeteer server. + + + ```python + result = await self.client.request( + { + "method": "tools/call", + "params": { + "name": "navigate", + "arguments": {"url": url} + } + }, + schema=CallToolResultSchema + ) + ``` + Tools let you take actions through MCP servers. Here we're using puppeteer's navigate tool. + + + ```python + result = await self.client.request( + { + "method": "resources/read", + "params": {"uri": "console://logs"} + }, + schema=ReadResourceResultSchema + ) + ``` + Resources provide data from MCP servers. Here we're reading console logs that puppeteer collected. + + + +## Enhancement ideas + +Now that you have MCP working, here are some ways to enhance the analyzer: + + + ```python + # Take screenshots with puppeteer + await client.request({ + "method": "tools/call", + "params": { + "name": "screenshot", + "arguments": {...} + } + }) + ``` + + + ```python + # Analyze multiple pages in sequence + for url in urls: + await navigate(url) + await analyze() + ``` + + + ```python + # Test interactive features + await client.request({ + "method": "tools/call", + "params": { + "name": "click", + "arguments": {"selector": "button"} + } + }) + ``` + + + +Common Patterns +Here are some patterns you'll often use when integrating MCP: + + + When you need to wait for resource updates: + ```python + async def wait_for_resource(uri: str, timeout: int = 30): + start = time.time() + while time.time() - start < timeout: + result = await client.request( + { + "method": "resources/read", + "params": {"uri": uri} + }, + schema=ReadResourceResultSchema + ) + if some_condition(result): + return result + await asyncio.sleep(1) + raise TimeoutError() + ``` + + + Robust error handling for MCP operations: + ```python + try: + await client.request(...) + except MCPError as e: + if e.code == ErrorCode.ResourceNotFound: + # Handle missing resource + elif e.code == ErrorCode.InvalidRequest: + # Handle invalid parameters + else: + # Handle other errors + ``` + + + Subscribe to resource updates: + ```python + await client.request( + { + "method": "resources/subscribe", + "params": {"uri": "console://logs"} + }, + schema=EmptyResultSchema + ) + # Now you'll get notifications when logs change + ``` + + + +## Troubleshooting + + + + ```python + # Enable debug logging + import logging + logging.basicConfig(level=logging.DEBUG) + ``` + Watch for connection errors and MCP protocol messages. + + + 1. Check if the resource exists: + ```python + resources = await client.request( + {"method": "resources/list"}, + schema=ListResourcesResultSchema + ) + print(resources) + ``` + 2. Verify URI format + 3. Check server logs + + + 1. List available tools: + ```python + tools = await client.request( + {"method": "tools/list"}, + schema=ListToolsResultSchema + ) + print(tools) + ``` + 2. Check argument schema + 3. Verify server capabilities + + + +## Next steps + + + + Connect to additional MCP servers for more capabilities + + +Create your own MCP server for custom functionality + + \ No newline at end of file diff --git a/docs/guides/integrate-ts.mdx b/docs/guides/integrate-ts.mdx new file mode 100644 index 0000000..fdb3a2e --- /dev/null +++ b/docs/guides/integrate-ts.mdx @@ -0,0 +1,885 @@ +--- +title: "Integrate MCP into Your TypeScript App" +description: "Add MCP support to your LLM application in TypeScript" +--- + +Learn how to integrate MCP into your TypeScript/React application. We'll build an AI Web Analyzer that uses Claude to analyze websites, enhanced with MCP's web automation capabilities. + + +This guide uses an existing MCP server ([puppeteer](/servers/puppeteer)) rather than building one from scratch. This lets us focus on the integration patterns. + + +## The example app + +We'll build an "AI Web Analyzer" that: +1. Takes a URL from the user +2. Captures the webpage using MCP +3. Has Claude analyze the page's content, design, and accessibility + + + Screenshot of the Web Analyzer interface + + +## Prerequisites + + + + ```bash + # Create new Next.js project with TypeScript + npx create-next-app@latest web-analyzer --typescript --tailwind + cd web-analyzer + ``` + + + + ```bash + npm install @modelcontextprotocol/sdk @anthropic-ai/sdk + ``` + + + + ```bash + # Install example MCP servers + git clone https://github.com/modelcontextprotocol/example-servers + cd example-servers + npm install + npm run build + npm install -g + ``` + + + +## Building the base app + +First, let's create a basic version without MCP: + + + + Create `components/WebAnalyzer.tsx`: + + ```tsx + import { useState } from 'react'; + import Anthropic from '@anthropic-ai/sdk'; + + const anthropic = new Anthropic({ + apiKey: process.env.NEXT_PUBLIC_ANTHROPIC_API_KEY + }); + + export default function WebAnalyzer() { + const [url, setUrl] = useState(''); + const [analysis, setAnalysis] = useState(''); + const [loading, setLoading] = useState(false); + + const analyzeUrl = async () => { + setLoading(true); + try { + const response = await anthropic.messages.create({ + model: 'claude-3-opus-20240229', + max_tokens: 1000, + messages: [{ + role: 'user', + content: `Please analyze this website: ${url}\n\n` + + `I'd like to know about:\n` + + `1. Content quality and organization\n` + + `2. Visual design (based on URL/description)\n` + + `3. Potential improvements` + }] + }); + setAnalysis(response.content[0].text); + } catch (error) { + console.error('Error:', error); + setAnalysis('Error analyzing website'); + } + setLoading(false); + }; + + return ( +
+

+ AI Web Analyzer +

+ +
+ setUrl(e.target.value)} + placeholder="Enter website URL" + className="flex-1 p-2 border rounded" + /> + +
+ + {loading && ( +
+ Analyzing website... +
+ )} + + {analysis && ( +
+
{analysis}
+
+ )} +
+ ); + } + ``` +
+ + + Update `app/page.tsx`: + + ```tsx + import WebAnalyzer from '@/components/WebAnalyzer'; + + export default function Home() { + return ( +
+ +
+ ); + } + ``` +
+ + + Create `.env.local`: + + ```bash + NEXT_PUBLIC_ANTHROPIC_API_KEY=your-key-here + ``` + +
+ +## Adding MCP support + +Now let's enhance the app with MCP capabilities: + + + + Create `lib/mcp.ts`: + + ```typescript + import { Client } from '@modelcontextprotocol/sdk/client'; + import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio'; + import { + CallToolResultSchema, + ReadResourceResultSchema + } from '@modelcontextprotocol/sdk/types'; + + export class MCPWebClient { + private client: Client; + private transport: StdioClientTransport | null = null; + + constructor() { + this.client = new Client({ + name: 'web-analyzer', + version: '0.1.0' + }); + } + + async connect() { + this.transport = new StdioClientTransport({ + command: 'mcp-server-puppeteer' + }); + await this.client.connect(this.transport); + } + + async navigate(url: string): Promise { + try { + const result = await this.client.request( + { + method: 'tools/call', + params: { + name: 'navigate', + arguments: { url } + } + }, + CallToolResultSchema + ); + return result.toolResult as string; + } catch (error) { + console.error('Error navigating:', error); + return null; + } + } + + async getConsoleLogs(): Promise { + const result = await this.client.request( + { + method: 'resources/read', + params: { uri: 'console://logs' } + }, + ReadResourceResultSchema + ); + return result.contents[0].text; + } + + async close() { + if (this.transport) { + await this.client.close(); + } + } + } + ``` + + + + Create `contexts/MCPContext.tsx`: + + ```typescript + import { createContext, useContext, useEffect, useRef } from 'react'; + import { MCPWebClient } from '@/lib/mcp'; + + const MCPContext = createContext(null); + + export function MCPProvider({ children }: { children: React.ReactNode }) { + const clientRef = useRef(null); + + useEffect(() => { + const initMCP = async () => { + clientRef.current = new MCPWebClient(); + await clientRef.current.connect(); + }; + + initMCP(); + + return () => { + if (clientRef.current) { + clientRef.current.close(); + } + }; + }, []); + + return ( + + {children} + + ); + } + + export function useMCP() { + const context = useContext(MCPContext); + if (!context) { + throw new Error('useMCP must be used within MCPProvider'); + } + return context; + } + ``` + + + + Update `components/WebAnalyzer.tsx`: + + ```typescript + import { useState } from 'react'; + import Anthropic from '@anthropic-ai/sdk'; + import { useMCP } from '@/contexts/MCPContext'; + + const anthropic = new Anthropic({ + apiKey: process.env.NEXT_PUBLIC_ANTHROPIC_API_KEY + }); + + export default function WebAnalyzer() { + const mcp = useMCP(); + const [url, setUrl] = useState(''); + const [analysis, setAnalysis] = useState(''); + const [loading, setLoading] = useState(false); + + const analyzeUrl = async () => { + setLoading(true); + try { + // Navigate to the URL with MCP + await mcp.navigate(url); + + // Get console logs + const consoleLogs = await mcp.getConsoleLogs(); + + // Analyze with Claude + const response = await anthropic.messages.create({ + model: 'claude-3-opus-20240229', + max_tokens: 1000, + messages: [{ + role: 'user', + content: `Please analyze this website: ${url}\n\n` + + `Here are the browser console logs:\n${consoleLogs}\n\n` + + `Please analyze:\n` + + `1. Content quality and organization\n` + + `2. Visual design\n` + + `3. Technical issues (based on console logs)\n` + + `4. Potential improvements` + }] + }); + setAnalysis(response.content[0].text); + } catch (error) { + console.error('Error:', error); + setAnalysis('Error analyzing website'); + } + setLoading(false); + }; + + // ... rest of the component remains the same + } + ``` + + + + Update `app/layout.tsx`: + + ```typescript + import { MCPProvider } from '@/contexts/MCPContext'; + + export default function RootLayout({ + children, + }: { + children: React.ReactNode + }) { + return ( + + + + {children} + + + + ); + } + ``` + + + +## Understanding MCP integration + +Let's break down the key components: + + + + ```typescript + export class MCPWebClient { + private client: Client; + + constructor() { + this.client = new Client({ + name: 'web-analyzer', + version: '0.1.0' + }); + } + } + ``` + The MCP client manages the connection to MCP servers and handles requests. + + + + ```typescript + export function MCPProvider({ children }: { children: React.ReactNode }) { + const clientRef = useRef(null); + + useEffect(() => { + const initMCP = async () => { + clientRef.current = new MCPWebClient(); + await clientRef.current.connect(); + }; + + initMCP(); + // ... cleanup + }, []); + } + ``` + The context provider manages the MCP client lifecycle. + + + + ```typescript + async navigate(url: string): Promise { + const result = await this.client.request( + { + method: 'tools/call', + params: { + name: 'navigate', + arguments: { url } + } + }, + CallToolResultSchema + ); + return result.toolResult as string; + } + ``` + Tools let you take actions through MCP servers. + + + + ```typescript + async getConsoleLogs(): Promise { + const result = await this.client.request( + { + method: 'resources/read', + params: { uri: 'console://logs' } + }, + ReadResourceResultSchema + ); + return result.contents[0].text; + } + ``` + Resources provide data from MCP servers. + + + +## Enhancement ideas + +Here are some ways to enhance the analyzer: + + + + ```typescript + // Add screenshot capability + async function captureScreenshot() { + const result = await mcp.client.request({ + method: 'tools/call', + params: { + name: 'screenshot', + arguments: { /* ... */ } + } + }); + } + ``` + + + + ```typescript + // Analyze multiple pages + async function analyzeBatch(urls: string[]) { + const results = []; + for (const url of urls) { + await mcp.navigate(url); + // ... analyze + } + } + ``` + + + + ```typescript + // Test interactive elements + async function testInteraction() { + await mcp.client.request({ + method: 'tools/call', + params: { + name: 'click', + arguments: { selector: 'button' } + } + }); + } + ``` + + + + ```typescript + // Add performance metrics + async function getPerformance() { + const metrics = await mcp.client.request({ + method: 'resources/read', + params: { uri: 'metrics://performance' } + }); + } + ``` + + + +## Common patterns + +Here are some patterns you'll often use with MCP in React: + + + + ```typescript + function useResourcePolling(uri: string, interval = 1000) { + const [data, setData] = useState(null); + + useEffect(() => { + let mounted = true; + + async function poll() { + while (mounted) { + const result = await mcp.client.request({ + method: 'resources/read', + params: { uri } + }); + if (mounted) { + setData(result); + await new Promise(r => setTimeout(r, interval)); + } + } + } + + poll(); + return () => { mounted = false; }; + }, [uri, interval]); + + return data; + } + ``` + + + + ```typescript + class MCPErrorBoundary extends React.Component { + state = { hasError: false }; + + static getDerivedStateFromError(error) { + return { hasError: true }; + } + + componentDidCatch(error, errorInfo) { + if (error instanceof MCPError) { + // Handle MCP-specific errors + } + } + + render() { + if (this.state.hasError) { + return ; + } + return this.props.children; + } + } + ``` + + + + ```typescript + function useResourceSubscription(uri: string) { + useEffect(() => { + mcp.client.request({ + method: 'resources/subscribe', + params: { uri } + }); + + return () => { + mcp.client.request({ + method: 'resources/unsubscribe', + params: { uri } + }); + }; + }, [uri]); + } + ``` + + + +## Troubleshooting + + + + ```typescript + // Enable debug logging + const initMCP = async () => { + const client = new MCPWebClient({ + debug: true, // Enable debug logging + onError: (error) => { + console.error('MCP Error:', error); + } + }); + await client.connect(); + }; + ``` + Watch the browser console for connection errors and protocol messages. + + + + Common issues and solutions: + ```typescript + function WebAnalyzer() { + // Don't create client on every render + const mcpRef = useRef(null); + + // Initialize in useEffect + useEffect(() => { + const init = async () => { + mcpRef.current = new MCPWebClient(); + await mcpRef.current.connect(); + }; + init(); + + // Clean up properly + return () => { + if (mcpRef.current) { + mcpRef.current.close(); + } + }; + }, []); + } + ``` + + + + Use TypeScript to catch MCP issues early: + ```typescript + // Define expected response types + interface ToolResponse { + toolResult: { + screenshot?: string; + logs?: string[]; + error?: string; + }; + } + + // Use with request + const result = await client.request({ + method: 'tools/call', + params: { + name: 'screenshot', + arguments: { /* ... */ } + } + }); + + // TypeScript will catch missing properties + console.log(result.toolResult.screenshot); + ``` + + + +## Performance optimization + + + + ```typescript + function useCachedResource(uri: string) { + const [data, setData] = useState(null); + const cache = useRef(new Map()); + + useEffect(() => { + async function fetchResource() { + if (cache.current.has(uri)) { + setData(cache.current.get(uri)!); + return; + } + + const result = await mcp.client.request({ + method: 'resources/read', + params: { uri } + }); + + cache.current.set(uri, result.contents[0].text); + setData(result.contents[0].text); + } + + fetchResource(); + }, [uri]); + + return data; + } + ``` + + + + ```typescript + class BatchedMCPClient extends MCPWebClient { + private batchQueue: Map>; + + async request(method: string, params: any) { + const key = JSON.stringify({ method, params }); + + if (!this.batchQueue.has(key)) { + this.batchQueue.set( + key, + super.request(method, params) + ); + + // Clear after resolution + this.batchQueue.get(key)!.finally(() => { + this.batchQueue.delete(key); + }); + } + + return this.batchQueue.get(key); + } + } + ``` + + + +## Building for production + + + + Add proper error boundaries: + + ```typescript + import { ErrorBoundary } from 'react-error-boundary'; + + function ErrorFallback({ error, resetErrorBoundary }) { + return ( +
+

Something went wrong:

+
{error.message}
+ +
+ ); + } + + export default function App() { + return ( + { + // Reset application state + }} + > + + + ); + } + ``` +
+ + + Add proper loading indicators: + + ```typescript + function WebAnalyzer() { + const [state, setState] = useState<{ + status: 'idle' | 'loading' | 'success' | 'error'; + error?: Error; + data?: string; + }>({ + status: 'idle' + }); + + return ( +
+ {state.status === 'loading' && ( +
+
+
+
+
+
+
+ )} + + {state.status === 'error' && ( +
+ {state.error?.message} +
+ )} + + {state.status === 'success' && ( +
{state.data}
+ )} +
+ ); + } + ``` +
+ + + Set up proper environment variables: + + ```typescript + // next.config.js + module.exports = { + env: { + NEXT_PUBLIC_ANTHROPIC_API_KEY: process.env.NEXT_PUBLIC_ANTHROPIC_API_KEY, + MCP_DEBUG: process.env.NODE_ENV === 'development' + } + }; + + // Usage in code + const mcpClient = new MCPWebClient({ + debug: process.env.MCP_DEBUG === 'true' + }); + ``` + +
+ +## Security considerations + + +Always validate and sanitize URLs before passing them to MCP servers. The puppeteer server has access to execute JavaScript and interact with web pages. + + +```typescript +function validateUrl(url: string): boolean { + try { + const parsed = new URL(url); + // Add your validation rules + return parsed.protocol === 'https:'; + } catch { + return false; + } +} + +function WebAnalyzer() { + const analyzeUrl = async () => { + if (!validateUrl(url)) { + setError('Please enter a valid HTTPS URL'); + return; + } + // ... rest of the analysis code + }; +} +``` + +## Next steps + + + + Learn how to handle authenticated web pages with MCP + + + Build your own MCP server for custom functionality + + + Learn how to test MCP integrations + + + Deploy your MCP-enabled app to production + + + + + + diff --git a/docs/guides/testing-debugging.mdx b/docs/guides/testing-debugging.mdx deleted file mode 100644 index a936680..0000000 --- a/docs/guides/testing-debugging.mdx +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: "Testing and Debugging" -description: "Test and debug your MCP servers effectively" ---- - -# Testing and Debugging - -Test and debug your MCP servers effectively diff --git a/docs/guides/working-with-resources.mdx b/docs/guides/working-with-resources.mdx deleted file mode 100644 index f77ad53..0000000 --- a/docs/guides/working-with-resources.mdx +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: "Working with Resources" -description: "Learn how to expose and consume data through MCP" ---- - -# Working with Resources - -Learn how to expose and consume data through MCP diff --git a/docs/installation.mdx b/docs/installation.mdx deleted file mode 100644 index 66ffc35..0000000 --- a/docs/installation.mdx +++ /dev/null @@ -1,160 +0,0 @@ ---- -title: "Installation" -description: "Get started with Model Context Protocol (MCP) by installing the SDK for your preferred language" ---- - - - MCP supports both TypeScript and Python implementations. Choose the one that best fits your project. - - - - - - - Install the TypeScript SDK using npm: - ```bash - npm install @modelcontextprotocol/sdk - ``` - - - Install the Python SDK using pip: - ```bash - pip install modelcontextprotocol - ``` - - - - - - Verify your installation by running a simple test: - - - ```typescript typescript-test.ts - import { Client } from "@modelcontextprotocol/sdk"; - - const client = new Client({ - name: "test-client", - version: "0.1.0" - }); - console.log("MCP SDK installed successfully!"); - ``` - - ```python python-test.py - from modelcontextprotocol import Client - - client = Client( - name="test-client", - version="0.1.0" - ) - print("MCP SDK installed successfully!") - ``` - - - - - - For local development, you'll need Node.js 18+ for TypeScript or Python 3.8+ for Python. - - - Install the MCP Inspector for testing and debugging your implementations: - ```bash - npm install -g @modelcontextprotocol/inspector - ``` - - - -## System Requirements - - - - - Node.js 18 or higher - - npm 7 or higher - - TypeScript 4.7 or higher (for TypeScript users) - - Optional development tools: - - VS Code with TypeScript plugin - - ESLint for code quality - - - - - Python 3.8 or higher - - pip 20.0 or higher - - virtualenv (recommended) - - Optional development tools: - - VS Code with Python extension - - pylint for code quality - - - - MCP supports all major operating systems: - - Windows 10/11 - - macOS 10.15+ - - Linux (major distributions) - - - -## Architecture Overview - - - - - -```mermaid -flowchart LR - A[LLM Application] --> B[MCP Client] - B --> C[MCP Server] - C --> D[(External Resource)] - - style A fill:#e0f4ff,stroke:#0077cc,stroke-width:2px - style B fill:#fff4e0,stroke:#ff8c00,stroke-width:2px - style C fill:#e0ffe0,stroke:#2d862d,stroke-width:2px - style D fill:#ffe0e0,stroke:#cc0000,stroke-width:2px - - classDef default fill:#f9f9f9,stroke:#333,stroke-width:1px - -## Next Steps - - - Build your first MCP integration in under 5 minutes - - - Explore pre-built MCP servers for common use cases - - - Dive into the complete API documentation - - - - Join our [Discord community](https://discord.gg/mcp) for help and discussions about MCP development. - - -## Troubleshooting Common Issues - - - - If you encounter version conflicts, ensure all your dependencies are up to date: - ```bash - # For TypeScript - npm update @modelcontextprotocol/sdk -Copy# For Python -pip install --upgrade modelcontextprotocol -``` - - - If you're having trouble connecting to MCP servers: - 1. Check your network configuration - 2. Verify the server is running - 3. Ensure your firewall isn't blocking connections - 4. Check the server logs for errors - - - Common build errors and their solutions: - - TypeScript type errors: Update your @types dependencies - - Python import errors: Check your PYTHONPATH - - Missing dependencies: Run package manager install commands - - - - Remember to keep your SDKs updated to the latest version for security patches and new features. - diff --git a/docs/recipes/api-integration.mdx b/docs/recipes/api-integration.mdx deleted file mode 100644 index f3787b0..0000000 --- a/docs/recipes/api-integration.mdx +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: "API Integration" -description: "Wrap external APIs with MCP" ---- - -# API Integration - -Wrap external APIs with MCP diff --git a/docs/recipes/database-integration.mdx b/docs/recipes/database-integration.mdx deleted file mode 100644 index dbcf630..0000000 --- a/docs/recipes/database-integration.mdx +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: "Database Integration" -description: "Connect databases to your LLM through MCP" ---- - -# Database Integration - -Connect databases to your LLM through MCP diff --git a/docs/recipes/local-files.mdx b/docs/recipes/local-files.mdx deleted file mode 100644 index fb592b4..0000000 --- a/docs/recipes/local-files.mdx +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: "Local File Access" -description: "Implement local file access in MCP" ---- - -# Local File Access - -Implement local file access in MCP diff --git a/docs/recipes/realtime-updates.mdx b/docs/recipes/realtime-updates.mdx deleted file mode 100644 index a7d2b58..0000000 --- a/docs/recipes/realtime-updates.mdx +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: "Real-time Updates" -description: "Handle live data updates in MCP" ---- - -# Real-time Updates - -Handle live data updates in MCP diff --git a/introduction.mdx b/introduction.mdx index 9f6743d..e9a1f4f 100644 --- a/introduction.mdx +++ b/introduction.mdx @@ -1,63 +1,142 @@ --- title: Introduction -description: 'Introduction to the Model Context Protocol' +description: 'Get started with the Model Context Protocol (MCP)' --- -The Model Context Protocol (MCP) is a protocol designed to enable LLM assistant surfaces to receive contextual information from specialized servers. Whether youโ€™re building an IDE coding assistant, a chat interface, or any other LLM-powered application, MCP provides a standardized way to obtain and utilize relevant context. +The Model Context Protocol (MCP) is an open protocol that enables seamless integration between LLM applications and external data sources and tools. Whether you're building an AI-powered IDE, enhancing a chat interface, or creating custom AI workflows, MCP provides a standardized way to connect LLMs with the context they need. +## Quickstart Guides -## Get started - -The first step to world-class documentation is setting up your editing environments. +Choose the path that best fits your needs: - Get your docs set up locally for easy development + The fastest way to see MCP in action - connect example servers to Claude in minutes - Preview your changes before you push to make sure they're perfect - - - -## Make it yours - -Update your docs to your brand and add valuable content for the best user conversion. - - - - Customize your docs to your company's colors and brands - - - Automatically generate endpoints from an OpenAPI spec + Create a simple MCP server in TypeScript to understand the basics - Build interactive features and designs to guide your users + Create a simple MCP server in Python to understand the basics - Check out our showcase of our favorite documentation + Add MCP support to your TypeScript/JavaScript LLM application + + + Add MCP support to your Python LLM application + +## Explore MCP + +Dive deeper into MCP's core concepts and capabilities: + + + + Understand how MCP connects clients, servers, and LLMs + + + Expose data and content from your servers to LLMs + + + Create reusable prompt templates and workflows + + + Enable LLMs to perform actions through your server + + + Let your servers request completions from LLMs + + + Learn about MCP's communication mechanisms + + + +## Example Use Cases + +See what you can build with MCP: + + + + Connect your documentation, wikis, and internal knowledge bases to LLMs + + + Query databases and analyze results with natural language + + + Build AI-powered development tools with access to local files and git + + + Securely connect enterprise tools and data to AI interfaces + + + +## Security and Best Practices + +MCP is designed with security in mind, but requires careful implementation: + + + Learn about MCP's security model, best practices, and implementation guidelines + + +Want to contribute? Check out our [GitHub repository](https://github.com/modelcontextprotocol) or join our growing community of developers building with MCP. \ No newline at end of file diff --git a/logo/dark.svg b/logo/dark.svg index a628378..b5db00b 100644 --- a/logo/dark.svg +++ b/logo/dark.svg @@ -1,55 +1,17 @@ - - - - - - - - - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + diff --git a/logo/light.svg b/logo/light.svg index 582b3b9..0015bd1 100644 --- a/logo/light.svg +++ b/logo/light.svg @@ -1,51 +1,11 @@ - - - - - - - - - - - - - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + diff --git a/mint.json b/mint.json index b93e86e..cf87c99 100644 --- a/mint.json +++ b/mint.json @@ -2,8 +2,8 @@ "$schema": "https://mintlify.com/schema.json", "name": "Model Context Protocol", "logo": { - "dark": "/logo/dark.png", - "light": "/logo/light.png" + "dark": "/logo/dark.svg", + "light": "/logo/light.svg" }, "favicon": "/favicon.svg", "theme": "quill", @@ -49,38 +49,12 @@ { "group": "Get Started", "pages": [ - "quickstart", - "docs/installation", - "docs/key-concepts", - "docs/development" - ] - }, - { - "group": "Guides", - "pages": [ - "docs/guides/first-mcp-server", - "docs/guides/integrating-with-llm", - "docs/guides/working-with-resources", - "docs/guides/implementing-tools", - "docs/guides/security-best-practices", - "docs/guides/testing-debugging" - ] - }, - { - "group": "Recipes", - "pages": [ - "docs/recipes/local-files", - "docs/recipes/database-integration", - "docs/recipes/api-integration", - "docs/recipes/realtime-updates" - ] - }, - { - "group": "Deployment", - "pages": [ - "docs/deployment/environment-setup", - "docs/deployment/configuration", - "docs/deployment/monitoring" + "introduction", + "docs/guides/claude", + "docs/guides/first-server-python", + "docs/guides/first-server-ts", + "docs/guides/integrate-python", + "docs/guides/integrate-ts" ] }, { diff --git a/quickstart.mdx b/quickstart.mdx deleted file mode 100644 index 283553b..0000000 --- a/quickstart.mdx +++ /dev/null @@ -1,305 +0,0 @@ ---- -title: "Quickstart" -description: "Get started with MCP in less than 5 minutes" ---- - -Give Claude superpowers by connecting it to your local computer! This guide will show you how to set up Model Context Protocol (MCP) and experience its magic in just 5 minutes. - - -Model Context Protocol (MCP) is like giving Claude hands and eyes on your computer. It can: -- Take screenshots and analyze what's on your screen -- Read and analyze files from your computer -- Help you automate repetitive tasks -- Connect to your databases and local tools - -And it does all this while maintaining security - Claude can only access what you explicitly allow. - - -## Prerequisites - - -```bash macOS -# Check if you have Node.js installed -node --version # Should be v16 or higher - -# Check if you have git installed -git --version -``` - -```bash Installation -# Install Node.js from https://nodejs.org -# Install git from https://git-scm.com - -# Or use Homebrew -brew install node git -``` - - -## Quick Setup - - - - Let's start by getting some pre-built MCP servers that Claude can use: - - ```bash - # Clone the example servers - git clone https://github.com/modelcontextprotocol/example-servers - cd example-servers - - # Install dependencies and build - npm install - npm run build - - # Make servers available globally - npm install -g - ``` - - - - Open your Claude Desktop App configuration: - - ```bash - code ~/Library/Application\ Support/Claude/claude_desktop_config.json - ``` - - Add this configuration (replace YOUR_USERNAME with your actual username): - - ```json - { - "mcpServers": { - "osascript": { - "command": "mcp-server-osascript", - "env": { - "HOME": "/Users/YOUR_USERNAME" - } - } - } - } - ``` - - Save and **restart Claude Desktop App**. - - - - When you first use screen capture features, macOS will ask for permissions: - - Screenshot permissions dialog - - - Grant these permissions to Claude Desktop App: - - Screen Recording (for screenshots) - - Automation (for window management) - - - -## Try It Out! ๐ŸŽ‰ - -Now for the fun part! Try these examples to see MCP in action: - - - - Ask Claude: - ``` - Can you take a screenshot of my desktop and describe what you see? - ``` - - Claude will: - 1. Use MCP to capture your screen - 2. Add it as context to your conversation - 3. Analyze and describe what it sees - - Try follow-up questions like: - - "How many windows do I have open?" - - "What apps am I running?" - - "Is my battery level low?" - - - - Ask Claude: - ``` - I have several windows open and it's messy. Could you help me organize them? Maybe arrange my browser windows side by side? - ``` - - Claude will: - 1. Take a screenshot to assess the situation - 2. Use AppleScript to organize your windows - 3. Take another screenshot to confirm the changes - - Pro tip: You can ask Claude to create specific layouts or focus on particular apps! - - - - Ask Claude: - ``` - I often need to arrange my windows with: - - Browser on the left half - - VS Code on the top right quarter - - Terminal on the bottom right quarter - - Can you create an AppleScript to automate this layout? - ``` - - Claude will create a reusable script that you can save and run anytime! - - - -## What Just Happened? - - -Let's break down the magic: - -1. When you installed the `osascript` server, you gave Claude a way to: - - Take screenshots (see what you see) - - Run AppleScript (control your windows) - - Automate macOS tasks - -2. The MCP protocol lets Claude: - - Request these actions securely - - Get results back in real-time - - Chain actions together intelligently - -3. All of this happens locally on your machine - no data leaves your computer! - - -## Add More Capabilities - -Want to give Claude even more superpowers? Add these servers to your configuration: - - - - Add this to your config to let Claude read and analyze files: - ```json - "tee": { - "command": "mcp-server-tee", - "args": ["tail", "-f", "/var/log/system.log"], - "env": { - "HOME": "/Users/YOUR_USERNAME" - } - } - ``` - - - - Connect Claude to your PostgreSQL database: - ```json - "postgres": { - "command": "mcp-server-postgres", - "args": ["postgresql://localhost/mydb"], - "env": { - "HOME": "/Users/YOUR_USERNAME" - } - } - ``` - - - - Enable web automation capabilities: - ```json - "puppeteer": { - "command": "mcp-server-puppeteer", - "env": { - "HOME": "/Users/YOUR_USERNAME" - } - } - ``` - - - -## Quick Troubleshooting - - - - 1. Check if MCP is enabled: - - Click the ๐Ÿ”Œ icon in Claude - - You should see your configured servers - - 2. Verify your config: - ```bash - cat ~/Library/Application\ Support/Claude/claude_desktop_config.json - ``` - - 3. Restart Claude completely: - - Quit the app (not just close the window) - - Start it again - - - - Run this command to see Claude's logs: - ```bash - tail -f ~/Claude.log - ``` - - Common fixes: - - Check `HOME` env variable in your config - - Grant missing permissions in System Settings - - Try running example commands manually in Terminal - - - -## Pro Tips - - - - During development: - - Use Command+R to reload Claude - - This restarts MCP servers without closing Claude - - Perfect for testing config changes! - - - - Run multiple servers for maximum capability: - ```json - { - "mcpServers": { - "osascript": { ... }, - "postgres": { ... }, - "puppeteer": { ... }, - "tee": { ... } - } - } - ``` - - Now Claude can: - - Take screenshots - - Query your database - - Automate web tasks - - Read local files - - All in the same conversation! - - - - Add `"debug": true` to see what's happening: - ```json - { - "mcpServers": { - "osascript": { - "command": "mcp-server-osascript", - "env": { ... }, - "debug": true - } - } - } - ``` - - Then watch the logs: - ```bash - tail -f ~/Claude.log - ``` - - - -## Next Steps - - -Now that you've experienced MCP, you might want to: - -1. [Build your own MCP server](/mcp-dev) - Create custom integrations -2. [Explore example servers](https://github.com/modelcontextprotocol/example-servers) - See what's possible -3. Join our [community](/community) - Share your MCP creations! - - - -Remember: Claude will help you write MCP servers! Just describe what you want to build, and Claude can guide you through the process. - \ No newline at end of file From 93fdfb9a640db6821c8388ab10544e0bf1274b5d Mon Sep 17 00:00:00 2001 From: Zack Lee Date: Mon, 18 Nov 2024 08:49:41 -0500 Subject: [PATCH 3/6] removed DS_Store" --- .DS_Store | Bin 8196 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index c2cd63df2ba7efc55f73110e36efb638b6dcb733..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHM%Wl&^6upy%)*&K9h)UfcSz_CSv;m}wO$h0N1)B!J0#I;jlbSl7U^@vYij+0{ z1HZtQFX3NU!MQVTMz+TII;V41 zNNa8Y1^7e}dGrQ}(U?)dC}0#Y3K#{90{@}{cxJO%7d-d%Rg)V9i~^TZ0X`pWB*s>X z3ytdNK&CoTgpY@Ia{EEeZ`OaCK41)E z^r?ou=L5NqHRSv*k2Z?X$!2{~-=(Mq@?+qrl}- zKomROP8(xB`+1iiKF8WN(rY9(_FHIF6l5wK2dZ!!xctKqWgD){X{ET(h#HuA5uju+ KnNi@cD)1A~9Z{+P From c6b84b875f290a3e613d42a8a5d158b4369ed917 Mon Sep 17 00:00:00 2001 From: Zack Lee Date: Mon, 18 Nov 2024 09:09:49 -0500 Subject: [PATCH 4/6] quickstarts --- docs/core/architecture.mdx | 282 +++++++++++++++++ docs/core/prompts.mdx | 393 ++++++++++++++++++++++++ docs/core/resources.mdx | 197 ++++++++++++ docs/core/sampling.mdx | 221 +++++++++++++ docs/core/tools.mdx | 286 +++++++++++++++++ docs/core/transport.mdx | 278 +++++++++++++++++ docs/guides/first-server-python.mdx | 8 +- docs/guides/first-server-ts.mdx | 10 +- docs/guides/security-best-practices.mdx | 8 - docs/key-concepts.mdx | 12 - introduction.mdx | 12 +- mint.json | 11 + 12 files changed, 1683 insertions(+), 35 deletions(-) create mode 100644 docs/core/architecture.mdx create mode 100644 docs/core/prompts.mdx create mode 100644 docs/core/resources.mdx create mode 100644 docs/core/sampling.mdx create mode 100644 docs/core/tools.mdx create mode 100644 docs/core/transport.mdx delete mode 100644 docs/guides/security-best-practices.mdx delete mode 100644 docs/key-concepts.mdx diff --git a/docs/core/architecture.mdx b/docs/core/architecture.mdx new file mode 100644 index 0000000..c987d90 --- /dev/null +++ b/docs/core/architecture.mdx @@ -0,0 +1,282 @@ +--- +title: "Core Architecture" +description: "Understand how MCP connects clients, servers, and LLMs" +--- + +The Model Context Protocol (MCP) is built on a flexible, extensible architecture that enables seamless communication between LLM applications and external services. This document covers the core architectural components and concepts. + +## Overview + +MCP follows a client-server architecture where: + +- **Clients** are LLM applications (like claude.ai or IDEs) that initiate connections +- **Servers** provide context, tools, and prompts to clients +- **Hosts** are processes that run MCP clients + +```mermaid +flowchart LR + subgraph "Host (e.g., claude.ai)" + client[MCP Client] + end + subgraph "Server Process" + server[MCP Server] + end + + client <-->|Transport Layer| server +``` + +## Core components + +### Protocol Layer + +The protocol layer handles message framing, request/response linking, and high-level communication patterns. Key classes include: + +```typescript +class Protocol { + // Handle incoming requests + setRequestHandler(schema: T, handler: (request: T) => Result): void + + // Handle incoming notifications + setNotificationHandler(schema: T, handler: (notification: T) => void): void + + // Send requests and await responses + request(request: Request, schema: T): Promise + + // Send one-way notifications + notification(notification: Notification): Promise +} +``` + +### Transport layer + +The transport layer handles the actual communication between clients and servers. MCP supports multiple transport mechanisms: + +1. **stdio Transport** + - Uses standard input/output for communication + - Ideal for local processes + ```typescript + class StdioTransport implements Transport { + constructor(stdin: Readable, stdout: Writable) + send(message: JSONRPCMessage): Promise + } + ``` + +2. **WebSocket Transport** + - Enables real-time bidirectional communication + - Supports remote connections + ```typescript + class WebSocketTransport implements Transport { + constructor(url: URL) + send(message: JSONRPCMessage): Promise + } + ``` + +3. **SSE Transport** + - Uses Server-Sent Events for server-to-client messages + - HTTP POST for client-to-server messages + ```typescript + class SSETransport implements Transport { + constructor(url: URL) + send(message: JSONRPCMessage): Promise + } + ``` + +### Message types + +MCP uses JSON-RPC 2.0 as its message format with three main types: + +1. **Requests** + ```typescript + interface Request { + method: string + params?: { + _meta?: { + progressToken?: string | number + } + } + } + ``` + +2. **Notifications** + ```typescript + interface Notification { + method: string + params?: { + _meta?: Record + } + } + ``` + +3. **Results** + ```typescript + interface Result { + _meta?: Record + [key: string]: unknown + } + ``` + +## Connection lifecycle + +### 1. Initialization + +```mermaid +sequenceDiagram + participant Client + participant Server + + Client->>Server: initialize request + Server->>Client: initialize response + Client->>Server: initialized notification + + Note over Client,Server: Connection ready for use +``` + +1. Client sends `initialize` request with capabilities +2. Server responds with supported features +3. Client sends `initialized` notification +4. Normal message exchange begins + +### 2. Message Exchange + +After initialization, the following patterns are supported: + +- **Request-Response**: Client sends request, server responds +- **Notifications**: Either party sends one-way messages +- **Progress Updates**: Long-running operations can report progress +- **Resource Updates**: Servers notify about changed resources + +### 3. Termination + +Either party can terminate the connection: +- Clean shutdown via `close()` +- Transport disconnection +- Error conditions + +## Error handling + +MCP defines standard error codes and handling: + +```typescript +enum ErrorCode { + ConnectionClosed = -1, + ParseError = -32700, + InvalidRequest = -32600, + MethodNotFound = -32601, + InvalidParams = -32602, + InternalError = -32603 +} +``` + +Errors are propagated through: +- Error responses to requests +- Error events on transports +- Protocol-level error handlers + +## Implementation example + +Here's a basic example of implementing an MCP server: + +```typescript +import { Server } from "@modelcontextprotocol/sdk/server"; +import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio"; + +const server = new Server({ + name: "example-server", + version: "1.0.0" +}); + +// Handle requests +server.setRequestHandler(ListResourcesRequestSchema, async () => { + return { + resources: [ + { + uri: "example://resource", + name: "Example Resource" + } + ] + }; +}); + +// Connect transport +const transport = new StdioServerTransport(); +await server.connect(transport); +``` + +## Best practices + +### Transport selection + +1. **Local Communication** + - Use stdio transport for local processes + - Efficient for same-machine communication + - Simple process management + +2. **Remote Communication** + - WebSocket for full-duplex communication + - SSE for scenarios requiring HTTP compatibility + - Consider security implications + +### Message Handling + +1. **Request Processing** + - Validate inputs thoroughly + - Use type-safe schemas + - Handle errors gracefully + - Implement timeouts + +2. **Progress Reporting** + - Use progress tokens for long operations + - Report progress incrementally + - Include total progress when known + +3. **Error Management** + - Use appropriate error codes + - Include helpful error messages + - Clean up resources on errors + +## Security considerations + +1. **Transport Security** + - Use TLS for remote connections + - Validate connection origins + - Implement authentication when needed + +2. **Message Validation** + - Validate all incoming messages + - Sanitize inputs + - Check message size limits + - Verify JSON-RPC format + +3. **Resource Protection** + - Implement access controls + - Validate resource paths + - Monitor resource usage + - Rate limit requests + +4. **Error Handling** + - Don't leak sensitive information + - Log security-relevant errors + - Implement proper cleanup + - Handle DoS scenarios + +## Debugging and monitoring + +1. **Logging** + - Log protocol events + - Track message flow + - Monitor performance + - Record errors + +2. **Diagnostics** + - Implement health checks + - Monitor connection state + - Track resource usage + - Profile performance + +3. **Testing** + - Test different transports + - Verify error handling + - Check edge cases + - Load test servers + +This architecture provides a robust foundation for building MCP integrations while maintaining flexibility for different use cases and deployment scenarios. \ No newline at end of file diff --git a/docs/core/prompts.mdx b/docs/core/prompts.mdx new file mode 100644 index 0000000..d553287 --- /dev/null +++ b/docs/core/prompts.mdx @@ -0,0 +1,393 @@ +--- +title: "Prompts" +description: "Create resuable prompt templates and workflows" +--- + +MCP Prompts enable servers to define reusable prompt templates and workflows that clients can easily surface to users and LLMs. They provide a powerful way to standardize and share common LLM interactions. + +## Overview + +Prompts in MCP are predefined templates that can: +- Accept dynamic arguments +- Include context from resources +- Chain multiple interactions +- Guide specific workflows +- Surface as UI elements (like slash commands) + +## Prompt structure + +Each prompt is defined with: + +```typescript +{ + name: string; // Unique identifier for the prompt + description?: string; // Human-readable description + arguments?: [ // Optional list of arguments + { + name: string; // Argument identifier + description?: string; // Argument description + required?: boolean; // Whether argument is required + } + ] +} +``` + +## Discovering prompts + +Clients can discover available prompts through the `prompts/list` endpoint: + +```typescript +// Request +{ + method: "prompts/list" +} + +// Response +{ + prompts: [ + { + name: "analyze-code", + description: "Analyze code for potential improvements", + arguments: [ + { + name: "language", + description: "Programming language", + required: true + } + ] + } + ] +} +``` + +## Using prompts + +To use a prompt, clients make a `prompts/get` request: + +```typescript +// Request +{ + method: "prompts/get", + params: { + name: "analyze-code", + arguments: { + language: "python" + } + } +} + +// Response +{ + description?: string, // Optional context about the prompt + messages: [ // Messages to send to the LLM + { + role: "user" | "assistant", + content: { + type: "text" | "image", + text?: string, + data?: string, // base64 for images + mimeType?: string + } + } + ] +} +``` + +## Dynamic prompts + +Prompts can be dynamic and include: + +### Context Integration + +```typescript +const analyzeLogsPrompt = { + name: "analyze-logs", + description: "Analyze recent system logs", + arguments: [ + { + name: "timeframe", + description: "Time period to analyze", + required: true + } + ] +}; + +server.setRequestHandler(GetPromptRequestSchema, async (request) => { + if (request.params.name === "analyze-logs") { + const logs = await getSystemLogs(request.params.arguments?.timeframe); + return { + messages: [ + { + role: "user", + content: { + type: "text", + text: `Analyze these system logs and identify any issues:\n\n${logs}` + } + } + ] + }; + } +}); +``` + +### Resource references + +```typescript +const codeReviewPrompt = { + name: "review-code", + async getMessages(fileUri: string) { + const code = await readResource(fileUri); + return [ + { + role: "user", + content: { + type: "text", + text: `Review this code for best practices:\n\n${code}` + } + } + ]; + } +}; +``` + +### Multi-step workflows + +```typescript +const debugWorkflow = { + name: "debug-error", + async getMessages(error: string) { + return [ + { + role: "user", + content: { + type: "text", + text: "Here's an error I'm seeing:" + } + }, + { + role: "assistant", + content: { + type: "text", + text: "I'll help analyze this error. What have you tried so far?" + } + }, + { + role: "user", + content: { + type: "text", + text: error + } + } + ]; + } +}; +``` + +## Example implementation + +Here's a complete example of implementing prompts in an MCP server: + +```typescript +import { Server } from "@modelcontextprotocol/sdk/server"; +import { + ListPromptsRequestSchema, + GetPromptRequestSchema +} from "@modelcontextprotocol/sdk/types"; + +const PROMPTS = { + "git-commit": { + name: "git-commit", + description: "Generate a Git commit message", + arguments: [ + { + name: "changes", + description: "Git diff or description of changes", + required: true + } + ] + }, + "explain-code": { + name: "explain-code", + description: "Explain how code works", + arguments: [ + { + name: "code", + description: "Code to explain", + required: true + }, + { + name: "language", + description: "Programming language", + required: false + } + ] + } +}; + +const server = new Server({ + name: "example-prompts-server", + version: "1.0.0" +}); + +// List available prompts +server.setRequestHandler(ListPromptsRequestSchema, async () => { + return { + prompts: Object.values(PROMPTS) + }; +}); + +// Get specific prompt +server.setRequestHandler(GetPromptRequestSchema, async (request) => { + const prompt = PROMPTS[request.params.name]; + if (!prompt) { + throw new Error(`Prompt not found: ${request.params.name}`); + } + + if (request.params.name === "git-commit") { + return { + messages: [ + { + role: "user", + content: { + type: "text", + text: `Generate a concise but descriptive commit message for these changes:\n\n${request.params.arguments?.changes}` + } + } + ] + }; + } + + if (request.params.name === "explain-code") { + const language = request.params.arguments?.language || "Unknown"; + return { + messages: [ + { + role: "user", + content: { + type: "text", + text: `Explain how this ${language} code works:\n\n${request.params.arguments?.code}` + } + } + ] + }; + } + + throw new Error("Prompt implementation not found"); +}); +``` + +## Best practices + +When implementing prompts: + +1. Use clear, descriptive prompt names +2. Provide detailed descriptions for prompts and arguments +3. Validate all required arguments +4. Handle missing arguments gracefully +5. Consider versioning for prompt templates +6. Cache dynamic content when appropriate +7. Implement error handling +8. Document expected argument formats +9. Consider prompt composability +10. Test prompts with various inputs + +## UI integration + +Prompts can be surfaced in client UIs as: + +- Slash commands +- Quick actions +- Context menu items +- Command palette entries +- Guided workflows +- Interactive forms + +## Updates and changes + +Servers can notify clients about prompt changes: + +1. Server capability: `prompts.listChanged` +2. Notification: `notifications/prompts/list_changed` +3. Client re-fetches prompt list + +## Security considerations + +When implementing prompts: + +- Validate all arguments +- Sanitize user input +- Consider rate limiting +- Implement access controls +- Audit prompt usage +- Handle sensitive data appropriately +- Validate generated content +- Implement timeouts +- Consider prompt injection risks +- Document security requirements + +## Advanced features + +### Prompt chaining + +```typescript +const analyzePRPrompt = { + async getMessages(prId: string) { + // Chain multiple prompts + const diffPrompt = await getPrompt("analyze-diff"); + const testsPrompt = await getPrompt("review-tests"); + const securityPrompt = await getPrompt("security-review"); + + return [ + ...diffPrompt.messages, + ...testsPrompt.messages, + ...securityPrompt.messages + ]; + } +}; +``` + +### Context enrichment + +```typescript +const troubleshootPrompt = { + async getMessages(error: string) { + // Enrich with system context + const systemInfo = await getSystemInfo(); + const recentLogs = await getRecentLogs(); + const stackTrace = await parseError(error); + + return [ + { + role: "user", + content: { + type: "text", + text: `Help troubleshoot this error: +Error: ${error} +System: ${systemInfo} +Logs: ${recentLogs} +Stack: ${stackTrace}` + } + } + ]; + } +}; +``` + +### Interactive workflows + +```typescript +const debugWorkflow = { + async getMessages(stage: string, context: any) { + switch (stage) { + case "initial": + return promptForError(); + case "analysis": + return analyzeError(context.error); + case "solution": + return suggestFixes(context.analysis); + case "verification": + return verifyFix(context.solution); + } + } +}; +``` \ No newline at end of file diff --git a/docs/core/resources.mdx b/docs/core/resources.mdx new file mode 100644 index 0000000..517d629 --- /dev/null +++ b/docs/core/resources.mdx @@ -0,0 +1,197 @@ +--- +title: "Resources" +description: "Expose data and content from your servers to LLMs" +--- + +Resources are a core primitive in the Model Context Protocol (MCP) that allow servers to expose data and content that can be read by clients and used as context for LLM interactions. + +## Overview + +Resources represent any kind of data that an MCP server wants to make available to clients. This can include: + +- File contents +- Database records +- API responses +- Live system data +- Screenshots and images +- Log files +- And more + +Each resource is identified by a unique URI and can contain either text or binary data. + +## Resource URIs + +Resources are identified using URIs that follow this format: + +``` +[protocol]://[path] +``` + +For example: +- `file:///home/user/documents/report.pdf` +- `postgres://database/customers/schema` +- `screen://localhost/display1` + +The protocol and path structure is defined by the MCP server implementation. Servers can define their own custom URI schemes. + +## Resource types + +Resources can contain two types of content: + +### Text Resources + +Text resources contain UTF-8 encoded text data. These are suitable for: +- Source code +- Configuration files +- Log files +- JSON/XML data +- Plain text + +### Binary resources + +Binary resources contain raw binary data encoded in base64. These are suitable for: +- Images +- PDFs +- Audio files +- Video files +- Other non-text formats + +## Resource discovery + +Clients can discover available resources through two main methods: + +### Direct resources + +Servers expose a list of concrete resources via the `resources/list` endpoint. Each resource includes: + +```typescript +{ + uri: string; // Unique identifier for the resource + name: string; // Human-readable name + description?: string; // Optional description + mimeType?: string; // Optional MIME type +} +``` + +### Resource templates + +For dynamic resources, servers can expose URI templates that clients can use to construct valid resource URIs: + +```typescript +{ + uriTemplate: string; // URI template following RFC 6570 + name: string; // Human-readable name for this type + description?: string; // Optional description + mimeType?: string; // Optional MIME type for all matching resources +} +``` + +## Reading resources + +To read a resource, clients make a `resources/read` request with the resource URI. The server responds with: + +```typescript +{ + contents: [ + { + uri: string; // The requested URI + mimeType?: string; // Optional MIME type + + // One of: + text?: string; // For text resources + blob?: string; // For binary resources (base64 encoded) + } + ] +} +``` + +## Resource updates + +MCP supports real-time updates for resources through two mechanisms: + +### List changes + +Servers can notify clients when their list of available resources changes via the `notifications/resources/list_changed` notification. + +### Content changes + +Clients can subscribe to updates for specific resources: + +1. Client sends `resources/subscribe` with resource URI +2. Server sends `notifications/resources/updated` when the resource changes +3. Client can fetch latest content with `resources/read` +4. Client can unsubscribe with `resources/unsubscribe` + +## Example implementation + +Here's a simple example of implementing resource support in an MCP server: + +```typescript +const server = new Server({ + name: "example-server", + version: "1.0.0" +}); + +// List available resources +server.setRequestHandler(ListResourcesRequestSchema, async () => { + return { + resources: [ + { + uri: "file:///logs/app.log", + name: "Application Logs", + mimeType: "text/plain" + } + ] + }; +}); + +// Read resource contents +server.setRequestHandler(ReadResourceRequestSchema, async (request) => { + const uri = request.params.uri; + + if (uri === "file:///logs/app.log") { + const logContents = await readLogFile(); + return { + contents: [ + { + uri, + mimeType: "text/plain", + text: logContents + } + ] + }; + } + + throw new Error("Resource not found"); +}); +``` + +## Best practices + +When implementing resource support: + +1. Use clear, descriptive resource names and URIs +2. Include helpful descriptions to guide LLM understanding +3. Set appropriate MIME types when known +4. Implement resource templates for dynamic content +5. Use subscriptions for frequently changing resources +6. Handle errors gracefully with clear error messages +7. Consider pagination for large resource lists +8. Cache resource contents when appropriate +9. Validate URIs before processing +10. Document your custom URI schemes + +## Security considerations + +When exposing resources: + +- Validate all resource URIs +- Implement appropriate access controls +- Sanitize file paths to prevent directory traversal +- Be cautious with binary data handling +- Consider rate limiting for resource reads +- Audit resource access +- Encrypt sensitive data in transit +- Validate MIME types +- Implement timeouts for long-running reads +- Handle resource cleanup appropriately \ No newline at end of file diff --git a/docs/core/sampling.mdx b/docs/core/sampling.mdx new file mode 100644 index 0000000..21f9dbd --- /dev/null +++ b/docs/core/sampling.mdx @@ -0,0 +1,221 @@ +--- +title: "Sampling" +description: "Let your servers request completions from LLMs" +--- + +Sampling is a powerful MCP feature that allows servers to request LLM completions through the client, enabling sophisticated agentic behaviors while maintaining security and privacy. + +## How sampling works + +The sampling flow follows these steps: + +1. Server sends a `sampling/createMessage` request to the client +2. Client reviews the request and can modify it +3. Client samples from an LLM +4. Client reviews the completion +5. Client returns the result to the server + +This human-in-the-loop design ensures users maintain control over what the LLM sees and generates. + +## Message format + +Sampling requests use a standardized message format: + +```typescript +{ + messages: [ + { + role: "user" | "assistant", + content: { + type: "text" | "image", + // For text: + text?: string, + // For images: + data?: string, // base64 encoded + mimeType?: string + } + } + ], + systemPrompt?: string, + includeContext?: "none" | "thisServer" | "allServers", + temperature?: number, + maxTokens: number, + stopSequences?: string[], + metadata?: Record +} +``` + +## Request parameters + +### Messages + +The `messages` array contains the conversation history to send to the LLM. Each message has: + +- `role`: Either "user" or "assistant" +- `content`: The message content, which can be: + - Text content with a `text` field + - Image content with `data` (base64) and `mimeType` fields + +### System prompt + +An optional `systemPrompt` field allows servers to request a specific system prompt. The client may modify or ignore this. + +### Context inclusion + +The `includeContext` parameter specifies what MCP context to include: + +- `"none"`: No additional context +- `"thisServer"`: Include context from the requesting server +- `"allServers"`: Include context from all connected MCP servers + +The client controls what context is actually included. + +### Sampling parameters + +Fine-tune the LLM sampling with: + +- `temperature`: Controls randomness (0.0 to 1.0) +- `maxTokens`: Maximum tokens to generate +- `stopSequences`: Array of sequences that stop generation +- `metadata`: Additional provider-specific parameters + +## Response format + +The client returns a completion result: + +```typescript +{ + model: string, // Name of the model used + stopReason: "endTurn" | "stopSequence" | "maxTokens", + role: "user" | "assistant", + content: { + type: "text" | "image", + text?: string, + data?: string, + mimeType?: string + } +} +``` + +## Example implementation + +Here's an example of requesting sampling from a client: + +```typescript +// Server-side code +const response = await server.request({ + method: "sampling/createMessage", + params: { + messages: [ + { + role: "user", + content: { + type: "text", + text: "What files are in the current directory?" + } + } + ], + systemPrompt: "You are a helpful file system assistant.", + includeContext: "thisServer", + maxTokens: 100, + temperature: 0.7 + } +}, CreateMessageResultSchema); + +// Handle the completion +console.log(response.content.text); +``` + +## Best practices + +When implementing sampling: + +1. Always provide clear, well-structured prompts +2. Handle both text and image content appropriately +3. Set reasonable token limits +4. Include relevant context through `includeContext` +5. Validate responses before using them +6. Handle errors gracefully +7. Consider rate limiting sampling requests +8. Document expected sampling behavior +9. Test with various model parameters +10. Monitor sampling costs + +## Human-in-the-loop controls + +Sampling is designed with human oversight in mind: + +### For prompts + +- Clients should show users the proposed prompt +- Users should be able to modify or reject prompts +- System prompts can be filtered or modified +- Context inclusion is controlled by the client + +### For completions + +- Clients should show users the completion +- Users should be able to modify or reject completions +- Clients can filter or modify completions +- Users control which model is used + +## Security considerations + +When implementing sampling: + +- Validate all message content +- Sanitize sensitive information +- Implement appropriate rate limits +- Monitor sampling usage +- Encrypt data in transit +- Handle user data privacy +- Audit sampling requests +- Control cost exposure +- Implement timeouts +- Handle model errors gracefully + +## Common patterns + +### Agentic workflows + +Sampling enables agentic patterns like: + +- Reading and analyzing resources +- Making decisions based on context +- Generating structured data +- Handling multi-step tasks +- Providing interactive assistance + +### Context management + +Best practices for context: + +- Request minimal necessary context +- Structure context clearly +- Handle context size limits +- Update context as needed +- Clean up stale context + +### Error handling + +Robust error handling should: + +- Catch sampling failures +- Handle timeout errors +- Manage rate limits +- Validate responses +- Provide fallback behaviors +- Log errors appropriately + +## Limitations + +Be aware of these limitations: + +- Sampling depends on client capabilities +- Users control sampling behavior +- Context size has limits +- Rate limits may apply +- Costs should be considered +- Model availability varies +- Response times vary +- Not all content types supported \ No newline at end of file diff --git a/docs/core/tools.mdx b/docs/core/tools.mdx new file mode 100644 index 0000000..2697e84 --- /dev/null +++ b/docs/core/tools.mdx @@ -0,0 +1,286 @@ +--- +title: "Tools" +description: "Enable LLMs to perform actions through your server" +--- + +Tools are a powerful primitive in the Model Context Protocol (MCP) that enable servers to expose executable functionality to clients. Through tools, LLMs can interact with external systems, perform computations, and take actions in the real world. + +## How tools work + +Tools in MCP follow a request-response pattern where: + +1. Clients discover available tools through the `tools/list` endpoint +2. Clients can invoke tools using the `tools/call` endpoint +3. Servers execute the requested operation and return results +4. Progress updates can be sent during long-running operations + +## Tool definition structure + +Each tool is defined with the following structure: + +```typescript +{ + name: string; // Unique identifier for the tool + description?: string; // Human-readable description + inputSchema: { // JSON Schema for the tool's parameters + type: "object", + properties: { + // Tool-specific parameters + } + } +} +``` + +The `inputSchema` uses JSON Schema to define the expected parameters and their types. This enables: + +- Parameter validation +- Type checking +- Documentation of required vs optional parameters +- Complex nested parameter structures + +## Implementing tools + +Here's an example of implementing a basic tool in an MCP server: + +```typescript +const server = new Server({ + name: "example-server", + version: "1.0.0" +}); + +// Define available tools +server.setRequestHandler(ListToolsRequestSchema, async () => { + return { + tools: [{ + name: "calculate_sum", + description: "Add two numbers together", + inputSchema: { + type: "object", + properties: { + a: { type: "number" }, + b: { type: "number" } + }, + required: ["a", "b"] + } + }] + }; +}); + +// Handle tool execution +server.setRequestHandler(CallToolRequestSchema, async (request) => { + if (request.params.name === "calculate_sum") { + const { a, b } = request.params.arguments; + return { + toolResult: a + b + }; + } + throw new Error("Tool not found"); +}); +``` + +## Progress reporting + +For long-running operations, tools can report progress using the progress notification system: + +```typescript +server.setRequestHandler(CallToolRequestSchema, async (request) => { + if (request.params.name === "long_process") { + const progressToken = request.params._meta?.progressToken; + + for (let i = 0; i < total; i++) { + await doWork(); + + // Send progress update + await server.notification({ + method: "notifications/progress", + params: { + progress: i, + total: total, + progressToken + } + }); + } + + return { toolResult: "Complete" }; + } +}); +``` + +## Common tool patterns + +Here are some common patterns for implementing tools: + +### System operations + +Tools that interact with the local system: + +```typescript +{ + name: "execute_command", + description: "Run a shell command", + inputSchema: { + type: "object", + properties: { + command: { type: "string" }, + args: { type: "array", items: { type: "string" } } + } + } +} +``` + +### API integrations + +Tools that wrap external APIs: + +```typescript +{ + name: "github_create_issue", + description: "Create a GitHub issue", + inputSchema: { + type: "object", + properties: { + title: { type: "string" }, + body: { type: "string" }, + labels: { type: "array", items: { type: "string" } } + } + } +} +``` + +### Data processing + +Tools that transform or analyze data: + +```typescript +{ + name: "analyze_csv", + description: "Analyze a CSV file", + inputSchema: { + type: "object", + properties: { + filepath: { type: "string" }, + operations: { + type: "array", + items: { + enum: ["sum", "average", "count"] + } + } + } + } +} +``` + +## Best practices + +When implementing tools: + +1. Provide clear, descriptive names and descriptions +2. Use detailed JSON Schema definitions for parameters +3. Include examples in tool descriptions when helpful +4. Implement proper error handling and validation +5. Use progress reporting for long operations +6. Keep tool operations focused and atomic +7. Document expected return value structures +8. Implement proper timeouts +9. Consider rate limiting for resource-intensive operations +10. Log tool usage for debugging and monitoring + +## Security considerations + +When exposing tools: + +### Input validation + +- Validate all parameters against the schema +- Sanitize file paths and system commands +- Validate URLs and external identifiers +- Check parameter sizes and ranges +- Prevent command injection + +### Access control + +- Implement authentication where needed +- Use appropriate authorization checks +- Audit tool usage +- Rate limit requests +- Monitor for abuse + +### Error handling + +- Don't expose internal errors to clients +- Log security-relevant errors +- Handle timeouts appropriately +- Clean up resources after errors +- Validate return values + +## Tool discovery and updates + +MCP supports dynamic tool discovery: + +1. Clients can list available tools at any time +2. Servers can notify clients when tools change using `notifications/tools/list_changed` +3. Tools can be added or removed during runtime +4. Tool definitions can be updated (though this should be done carefully) + +## Common tool categories + +Tools typically fall into these categories: + +### System integration +- File operations +- Process management +- System information +- Network operations + +### External services +- API calls +- Database operations +- Authentication services +- Cloud services + +### Data processing +- Format conversion +- Data analysis +- Content generation +- Media processing + +### Device control +- Hardware interaction +- Device configuration +- Sensor reading +- Output control + +## Error handling + +Tools should return clear error information: + +```typescript +try { + // Tool operation +} catch (error) { + return { + toolResult: { + error: { + code: "OPERATION_FAILED", + message: "Failed to process request", + details: error.message + } + } + }; +} +``` + +## Testing tools + +Consider these testing approaches: + +1. Unit test parameter validation +2. Mock external dependencies +3. Test progress reporting +4. Verify error handling +5. Test concurrent execution +6. Validate return values +7. Test rate limiting +8. Check resource cleanup +9. Test timeout handling +10. Verify security constraints \ No newline at end of file diff --git a/docs/core/transport.mdx b/docs/core/transport.mdx new file mode 100644 index 0000000..e9e117c --- /dev/null +++ b/docs/core/transport.mdx @@ -0,0 +1,278 @@ +--- +title: "Transport" +description: "Learn about MCP's communication mechanisms" +--- + +Transport in the Model Context Protocol (MCP) provides the foundation for communication between clients and servers. It handles the underlying mechanics of how messages are sent and received. + +## How transport works + +MCP transport is built on a simple message-passing architecture where both clients and servers can send messages to each other. The transport layer is responsible for: + +- Establishing connections +- Sending messages +- Receiving messages +- Handling connection lifecycles +- Managing errors +- Ensuring reliable delivery + +## Available transport types + +MCP supports three main transport types: + +### Standard input/output (stdio) + +The stdio transport enables communication through standard input and output streams. This is particularly useful for local integrations and command-line tools. + +```typescript +// Server implementation +const server = new Server({ + name: "example-server", + version: "1.0.0" +}); + +const transport = new StdioServerTransport(); +await server.connect(transport); + +// Client implementation +const client = new Client({ + name: "example-client", + version: "1.0.0" +}); + +const transport = new StdioClientTransport({ + command: "./server", + args: ["--option", "value"] +}); +await client.connect(transport); +``` + +### WebSocket + +WebSocket transport provides real-time, bidirectional communication over a persistent connection. This is ideal for web-based applications that need low-latency messaging. + +```typescript +// Server implementation +const server = new Server({ + name: "example-server", + version: "1.0.0" +}); + +const transport = new WebSocketServerTransport(); +await server.connect(transport); + +// Client implementation +const client = new Client({ + name: "example-client", + version: "1.0.0" +}); + +const transport = new WebSocketClientTransport( + new URL("ws://localhost:3000") +); +await client.connect(transport); +``` + +### Server-sent events (SSE) + +SSE transport enables server-to-client streaming with HTTP POST requests for client-to-server communication. This is useful when WebSocket support isn't available. + +```typescript +// Server implementation +const server = new Server({ + name: "example-server", + version: "1.0.0" +}); + +const transport = new SSEServerTransport("/message", response); +await server.connect(transport); + +// Client implementation +const client = new Client({ + name: "example-client", + version: "1.0.0" +}); + +const transport = new SSEClientTransport( + new URL("http://localhost:3000/sse") +); +await client.connect(transport); +``` + +## Transport interface + +All transport implementations must conform to the Transport interface: + +```typescript +interface Transport { + // Start processing messages + start(): Promise; + + // Send a JSON-RPC message + send(message: JSONRPCMessage): Promise; + + // Close the connection + close(): Promise; + + // Callbacks + onclose?: () => void; + onerror?: (error: Error) => void; + onmessage?: (message: JSONRPCMessage) => void; +} +``` + +## Message format + +Messages sent over MCP transport follow the JSON-RPC 2.0 specification. There are three types of messages: + +### Requests + +```typescript +{ + jsonrpc: "2.0", + id: number | string, + method: string, + params?: object +} +``` + +### Responses + +```typescript +{ + jsonrpc: "2.0", + id: number | string, + result?: object, + error?: { + code: number, + message: string, + data?: unknown + } +} +``` + +### Notifications + +```typescript +{ + jsonrpc: "2.0", + method: string, + params?: object +} +``` + +## Error handling + +Transport implementations should handle various error scenarios: + +1. Connection errors +2. Message parsing errors +3. Protocol errors +4. Network timeouts +5. Resource cleanup + +Example error handling: + +```typescript +class ExampleTransport implements Transport { + async start() { + try { + // Connection logic + } catch (error) { + this.onerror?.(new Error(`Failed to connect: ${error}`)); + throw error; + } + } + + async send(message: JSONRPCMessage) { + try { + // Sending logic + } catch (error) { + this.onerror?.(new Error(`Failed to send message: ${error}`)); + throw error; + } + } +} +``` + +## Best practices + +When implementing or using MCP transport: + +1. Handle connection lifecycle properly +2. Implement proper error handling +3. Clean up resources on connection close +4. Use appropriate timeouts +5. Validate messages before sending +6. Log transport events for debugging +7. Implement reconnection logic when appropriate +8. Handle backpressure in message queues +9. Monitor connection health +10. Implement proper security measures + +## Security considerations + +When implementing transport: + +### Authentication and authorization + +- Implement proper authentication mechanisms +- Validate client credentials +- Use secure token handling +- Implement authorization checks + +### Data security + +- Use TLS for network transport +- Encrypt sensitive data +- Validate message integrity +- Implement message size limits +- Sanitize input data + +### Network security + +- Implement rate limiting +- Use appropriate timeouts +- Handle denial of service scenarios +- Monitor for unusual patterns +- Implement proper firewall rules + +## Debugging transport + +Tips for debugging transport issues: + +1. Enable debug logging +2. Monitor message flow +3. Check connection states +4. Validate message formats +5. Test error scenarios +6. Use network analysis tools +7. Implement health checks +8. Monitor resource usage +9. Test edge cases +10. Use proper error tracking + +## Transport selection guide + +Choose the appropriate transport based on your needs: + +### Use stdio when: + +- Building command-line tools +- Implementing local integrations +- Needing simple process communication +- Working with shell scripts + +### Use WebSocket when: + +- Real-time updates are needed +- Low latency is required +- Bidirectional communication is necessary +- Working with web applications + +### Use SSE when: + +- Only server-to-client streaming is needed +- WebSocket support is limited +- Working with restricted networks +- Implementing simple updates \ No newline at end of file diff --git a/docs/guides/first-server-python.mdx b/docs/guides/first-server-python.mdx index da5be94..7c512a2 100644 --- a/docs/guides/first-server-python.mdx +++ b/docs/guides/first-server-python.mdx @@ -45,7 +45,7 @@ This guide uses the OpenWeatherMap API. You'll need a free API key from [OpenWea -## Create Your Server +## Create your server @@ -269,7 +269,7 @@ This guide uses the OpenWeatherMap API. You'll need a free API key from [OpenWea -## Try It Out! +## Try it out! @@ -297,7 +297,7 @@ This guide uses the OpenWeatherMap API. You'll need a free API key from [OpenWea -## Understanding the Code +## Understanding the code Let's break down the key MCP concepts used in this server: @@ -346,7 +346,7 @@ Let's break down the key MCP concepts used in this server: -## Next Steps +## Next steps Now that you've built your first MCP server, try these enhancements: diff --git a/docs/guides/first-server-ts.mdx b/docs/guides/first-server-ts.mdx index c94021f..d3e0656 100644 --- a/docs/guides/first-server-ts.mdx +++ b/docs/guides/first-server-ts.mdx @@ -62,7 +62,7 @@ This guide uses the OpenWeatherMap API. You'll need a free API key from [OpenWea -## Create Your Server +## Create your server @@ -311,7 +311,7 @@ This guide uses the OpenWeatherMap API. You'll need a free API key from [OpenWea -## Try It Out! +## Try it out! @@ -336,7 +336,7 @@ This guide uses the OpenWeatherMap API. You'll need a free API key from [OpenWea -## Understanding the Code +## Understanding the code @@ -386,7 +386,7 @@ This guide uses the OpenWeatherMap API. You'll need a free API key from [OpenWea -## Best Practices +## Best practices -## Next Steps +## Next steps - This guide provides a high-level overview of MCP's core concepts. For detailed implementation guides, check out our tutorials section. - - -The Model Context Protocol (MCP) enables seamless integration between LLM applications and external data sources or tools. Let's break down the key concepts: - - diff --git a/introduction.mdx b/introduction.mdx index e9a1f4f..ec9c2f4 100644 --- a/introduction.mdx +++ b/introduction.mdx @@ -55,42 +55,42 @@ Dive deeper into MCP's core concepts and capabilities: Understand how MCP connects clients, servers, and LLMs Expose data and content from your servers to LLMs Create reusable prompt templates and workflows Enable LLMs to perform actions through your server Let your servers request completions from LLMs Learn about MCP's communication mechanisms diff --git a/mint.json b/mint.json index cf87c99..6fce8e4 100644 --- a/mint.json +++ b/mint.json @@ -57,6 +57,17 @@ "docs/guides/integrate-ts" ] }, + { + "group": "Concepts", + "pages": [ + "docs/core/architecture", + "docs/core/resources", + "docs/core/prompts", + "docs/core/tools", + "docs/core/sampling", + "docs/core/transport" + ] + }, { "group": "API Reference", "pages": [ From 4a3da62bee62d49b54292a670031966d5772a05f Mon Sep 17 00:00:00 2001 From: Zack Lee Date: Mon, 18 Nov 2024 09:11:33 -0500 Subject: [PATCH 5/6] cleanup --- README.md | 12 ++------ create-docs.sh | 75 -------------------------------------------------- 2 files changed, 3 insertions(+), 84 deletions(-) delete mode 100644 create-docs.sh diff --git a/README.md b/README.md index 4cbe075..6c10353 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,6 @@ -# Mintlify Starter Kit +# Model Context Protocol Documentation -Click on `Use this template` to copy the Mintlify starter kit. The starter kit contains examples including - -- Guide pages -- Navigation -- Customizations -- API Reference pages -- Use of popular components +The official docs of MCP. This README is a WIP. ### Development @@ -24,7 +18,7 @@ mintlify dev ### Publishing Changes -Install our Github App to auto propagate changes from your repo to your deployment. Changes will be deployed to production automatically after pushing to the default branch. Find the link to install on your dashboard. +Install our Github App to auto propagate changes from your repo to your deployment. Changes will be deployed to production automatically after pushing to the default branch. Find the link to install on your dashboard. #### Troubleshooting diff --git a/create-docs.sh b/create-docs.sh deleted file mode 100644 index 03dda90..0000000 --- a/create-docs.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/bin/bash - -# Create base directories -mkdir -p docs/{guides,recipes,deployment,api,server-api,client-api,typescript,python} - -# Function to create an .mdx file with frontmatter -create_mdx() { - local filepath=$1 - local title=$2 - local description=$3 - - echo "Creating $filepath..." - cat > "$filepath" < Date: Mon, 18 Nov 2024 09:12:39 -0500 Subject: [PATCH 6/6] cleanup --- images/modelcontextprotocol.png | Bin 22447 -> 0 bytes your-first-server.mdx | 319 -------------------------------- 2 files changed, 319 deletions(-) delete mode 100644 images/modelcontextprotocol.png delete mode 100644 your-first-server.mdx diff --git a/images/modelcontextprotocol.png b/images/modelcontextprotocol.png deleted file mode 100644 index 8287430208a6ff1f08e4d1b8ccbf4b4a83bf2724..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22447 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
$aU=-l5zt;WYs!o{6h{39_HR z=iO<$s4MY*&1C?P&b6mqXu)f_JiA*jJDo!-mjE2pQC2<*UwvCu^SKT_8wQ^Yb1r>E z8ky7OMw2oexq`C&*rwUPEV+Vg5z{1ch^r+jA7GbnVSF$g#9j~;fB6@0k}?PF;D?O$ z9p7?Bp52$U3j}8qK`jC1^MTAkLS?ukD$!ji59?0vWKjs2h(~M=;^WN$kgI<9VaTu zBt8tkupCC?X z+Ndn6(H@^qE&?npT3G@3*l2v)s{DyqivsF|cX!cUhkoh6@w=qf`iM9(lb{Wg+wchb z_Tt@XFjx#7+b^}%CuSSSMg#%48XB|4C6wOepzJx@{|7+=TM+as5bV zxQQ$G>9ND{ONW0o7c@;{Afti^N#`-2KR6$u&AyjfV2~Bx$vrAGBxD3Ia&L#ug6&7x z?3bw<$#Z_3HzKg8!S z%VE3|OLNTx;&V(_Hb4CBSpDlBawZry5Zrxx3_)(8n?{$16s%0&xsAgbVG*N@ z7n;)7>t7>_Zh1bOb%5LP%oDi+5C}}v3S-nyGyxXG0R1W(q+f!vbS8E1$pSAc$;Hop zJ>WL!{h9PfR0WQ)G9)wwEOZ?URhhneSbHzo9mZr68Cqw$dY#BwAl?m(8h|-H_7H)r zj;#(kV_nSU&1%Gf^qNXq&@z-L?9S0+-3`{RTbGXaGA#gfL8>}BedN=r5r@LN8^`S! zv0=2~bV>5jT(^um0e(!y#j=QkHYM0eZd=;uS3v81JgW0XCO+6sl#VQ>t;9c(YLue)GK)(fH4fvFS?%!3oHgF0XJ>fDE9 zvl*sdB$wq5j>(xvP}8ICJIO<`0v3AEYZY=ZPp-$-VW)Mv(w>vLD*~-;``fmIJMmN{RQ-=Kudg|F<>zexB_#@1%vPD=G*6yO_7< Ll7(uIh@Jld#zI+e diff --git a/your-first-server.mdx b/your-first-server.mdx deleted file mode 100644 index c17200d..0000000 --- a/your-first-server.mdx +++ /dev/null @@ -1,319 +0,0 @@ ---- -title: "Your first MCP server" -description: "Get started with MCP by building a weather app in 5 minutes" ---- - -Connect AI to anything. MCP (Model Context Protocol) lets your AI applications seamlessly interact with data sources, tools, and services. - - - **Real-world example:** In this quickstart, we'll build an AI-powered weather app that lets users ask about current conditions in any city. Our app will use MCP to connect to a weather API. - - -![Weather App Demo](weather-app-demo.gif) - -## Installation - - - - ```bash - pip install mcp-sdk # Using pip - uv add mcp-sdk # Using uv (recommended) - ``` - - **Requirements:** - - Python 3.8 or higher - - pip or uv package manager - - - ```bash - npm install @modelcontextprotocol/sdk - ``` - - **Requirements:** - - Node.js 16 or higher - - TypeScript 4.7 or higher - - npm or yarn package manager - - - -## Step 1: Create an MCP Server - -Our server will expose a tool that the AI can use to fetch the current weather for any city. - - - - ```python weather_server.py - from mcp.server import Server - from mcp.server.stdio import stdio_server - import aiohttp - - server = Server("weather-server") - - @server.list_tools() - async def list_tools(): - return [{ - "name": "get_weather", - "description": "Get current weather for a city", - "inputSchema": { - "type": "object", - "properties": { - "city": {"type": "string"} - } - } - }] - - @server.call_tool() - async def call_tool(name: str, args: dict): - if name == "get_weather": - async with aiohttp.ClientSession() as session: - city = args["city"] - url = f"https://api.openweathermap.org/data/2.5/weather?q={city}&appid=YOUR_API_KEY" - async with session.get(url) as resp: - data = await resp.json() - return data["weather"][0]["description"] - - async def main(): - async with stdio_server() as (read, write): - await server.run(read, write) - - if __name__ == "__main__": - import asyncio - asyncio.run(main()) - ``` - - To make real API requests, sign up for a free API key at [OpenWeatherMap](https://openweathermap.org). - - - - ```typescript weather_server.ts - import { Server } from "@modelcontextprotocol/sdk/server"; - import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio"; - import axios from "axios"; - - const server = new Server({ - name: "weather-server", - version: "1.0.0", - }); - - server.setRequestHandler(ListToolsRequestSchema, async () => { - return { - tools: [{ - name: "get_weather", - description: "Get current weather for a city", - inputSchema: { - type: "object", - properties: { - city: { type: "string" } - } - } - }] - }; - }); - - server.setRequestHandler(CallToolRequestSchema, async (request) => { - if (request.params.name === "get_weather") { - const city = request.params.arguments?.city as string; - const url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=YOUR_API_KEY`; - const resp = await axios.get(url); - return { - toolResult: resp.data.weather[0].description - }; - } - throw new Error("Tool not found"); - }); - - async function main() { - const transport = new StdioServerTransport(); - await server.connect(transport); - } - - main().catch(console.error); - ``` - - To make real API requests, sign up for a free API key at [OpenWeatherMap](https://openweathermap.org). - - - -## Step 2: Integrate the Server into Your AI App - - - This example uses a mock AI model. In a real app, you would replace this with your actual AI model code that generates a response based on the user's message and any MCP context. - - - - - ```python app.py - from mcp.client import ClientSession - from mcp.client.stdio import stdio_client - import re - - def extract_city(message): - match = re.search(r"in\s+(\w+)", message) - if match: - return match.group(1) - else: - return None - - async def get_weather(city): - async with stdio_client(command="python weather_server.py") as (read, write): - async with ClientSession(read, write) as session: - await session.initialize() - return await session.call_tool("get_weather", {"city": city}) - - async def handle_message(message): - city = extract_city(message) - if city: - weather = await get_weather(city) - return f"The current weather in {city} is: {weather}" - else: - return generate_response(message) # Your existing AI logic - - async def main(): - while True: - message = input("> ") - response = await handle_message(message) - print(response) - - if __name__ == "__main__": - import asyncio - asyncio.run(main()) - ``` - - - - ```typescript app.ts - import { Client } from "@modelcontextprotocol/sdk/client"; - import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio"; - import { CallToolResultSchema } from "@modelcontextprotocol/sdk/types"; - import readline from "readline"; - - function extractCity(message: string): string | null { - const match = message.match(/in\s+(\w+)/); - if (match) { - return match[1]; - } else { - return null; - } - } - - async function getWeather(city: string): Promise { - const transport = new StdioClientTransport({ - command: "ts-node weather_server.ts", - }); - const client = new Client({ - name: "weather-app", - version: "1.0.0", - }); - await client.connect(transport); - const result = await client.request( - { - method: "tools/call", - params: { - name: "get_weather", - arguments: { city } - } - }, - CallToolResultSchema - ); - return result.toolResult as string; - } - - async function handleMessage(message: string): Promise { - const city = extractCity(message); - if (city) { - const weather = await getWeather(city); - return `The current weather in ${city} is: ${weather}`; - } else { - return generateResponse(message); // Your existing AI logic - } - } - - const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout - }); - - rl.prompt(); - rl.on("line", async (line) => { - const response = await handleMessage(line); - console.log(response); - rl.prompt(); - }); - ``` - - - -## Step 3: Run It! - - - - In one terminal, start the server: - ```bash - python weather_server.py - ``` - In another terminal, start the app: - ```bash - python app.py - ``` - - - In one terminal, start the server: - ```bash - ts-node weather_server.ts - ``` - In another terminal, start the app: - ```bash - ts-node app.ts - ``` - - - -Now chat with your AI assistant! Try asking about the weather in various cities. - -``` -> What's the weather like in Tokyo? -The current weather in Tokyo is: few clouds - -> How about London? -The current weather in London is: scattered clouds -``` - -## Why MCP Rocks - -- **Effortless integrations.** No custom code needed to connect AI to any API, database, or service. -- **Async built-in.** MCP client/server communication is fully asynchronous out of the box. -- **Type-safe.** Requests and responses are validated against strict schemas. - -## Next Steps - - - - Understand resources, tools, prompts and more - - - Databases, APIs, embeddings, vectorstores... - - - Expose your AI through an API or website - - - Ensure your app is rock solid - - - -## Getting Help - - - - Get support and see what others are building - - - Look up library classes and functions - - - Quick answers to common questions - - - Report bugs or suggest improvements - - \ No newline at end of file