From bee349287fbc83a0d8ea0bdf0817270cb364697b Mon Sep 17 00:00:00 2001 From: Evan Tahler Date: Mon, 13 Oct 2025 10:47:41 -0700 Subject: [PATCH] remove mkdocs for arcade-mcp (#617) Compainion to https://github.com/ArcadeAI/docs/pull/488 - This PR turns off MKDocs. We have the docs in docs.arcade.dev now. --- .github/workflows/test-docs.yml | 22 - libs/arcade-mcp-server/Makefile | 13 - .../docs/advanced/sharing-servers.md | 180 ------- .../docs/advanced/transports.md | 213 -------- libs/arcade-mcp-server/docs/api/mcp_app.md | 47 -- .../docs/api/server/errors.md | 36 -- .../docs/api/server/middleware.md | 50 -- .../docs/api/server/server.md | 53 -- .../docs/api/server/settings.md | 49 -- .../docs/api/server/types.md | 37 -- libs/arcade-mcp-server/docs/clients/claude.md | Bin 6557 -> 0 bytes libs/arcade-mcp-server/docs/clients/cursor.md | Bin 8263 -> 0 bytes .../docs/clients/inspector.md | 363 ------------- libs/arcade-mcp-server/docs/clients/vscode.md | 485 ------------------ .../docs/examples/00_hello_world.md | 22 - .../docs/examples/00_hello_world.py | 38 -- .../docs/examples/01_tools.md | 131 ----- .../docs/examples/01_tools.py | 130 ----- .../docs/examples/02_building_apps.md | 116 ----- .../docs/examples/02_building_apps.py | 66 --- .../docs/examples/03_context.md | 64 --- .../docs/examples/03_context.py | 155 ------ .../docs/examples/04_secrets.md | 59 --- .../docs/examples/04_secrets.py | 46 -- .../docs/examples/05_logging.md | 101 ---- .../docs/examples/05_logging.py | 190 ------- .../docs/examples/06_tool_organization.md | 191 ------- .../docs/examples/06_tool_organization.py | 94 ---- .../docs/examples/07_auth.md | 123 ----- .../docs/examples/07_auth.py | 73 --- .../arcade-mcp-server/docs/examples/README.md | 84 --- .../docs/examples/tools_math.py | 31 -- .../docs/examples/tools_text.py | 29 -- .../docs/getting-started/quickstart.md | 165 ------ libs/arcade-mcp-server/docs/index.md | 152 ------ libs/arcade-mcp-server/mkdocs.yml | 103 ---- libs/arcade-mcp-server/pyproject.toml | 3 - 37 files changed, 3714 deletions(-) delete mode 100644 .github/workflows/test-docs.yml delete mode 100644 libs/arcade-mcp-server/docs/advanced/sharing-servers.md delete mode 100644 libs/arcade-mcp-server/docs/advanced/transports.md delete mode 100644 libs/arcade-mcp-server/docs/api/mcp_app.md delete mode 100644 libs/arcade-mcp-server/docs/api/server/errors.md delete mode 100644 libs/arcade-mcp-server/docs/api/server/middleware.md delete mode 100644 libs/arcade-mcp-server/docs/api/server/server.md delete mode 100644 libs/arcade-mcp-server/docs/api/server/settings.md delete mode 100644 libs/arcade-mcp-server/docs/api/server/types.md delete mode 100644 libs/arcade-mcp-server/docs/clients/claude.md delete mode 100644 libs/arcade-mcp-server/docs/clients/cursor.md delete mode 100644 libs/arcade-mcp-server/docs/clients/inspector.md delete mode 100644 libs/arcade-mcp-server/docs/clients/vscode.md delete mode 100644 libs/arcade-mcp-server/docs/examples/00_hello_world.md delete mode 100644 libs/arcade-mcp-server/docs/examples/00_hello_world.py delete mode 100644 libs/arcade-mcp-server/docs/examples/01_tools.md delete mode 100644 libs/arcade-mcp-server/docs/examples/01_tools.py delete mode 100644 libs/arcade-mcp-server/docs/examples/02_building_apps.md delete mode 100644 libs/arcade-mcp-server/docs/examples/02_building_apps.py delete mode 100644 libs/arcade-mcp-server/docs/examples/03_context.md delete mode 100644 libs/arcade-mcp-server/docs/examples/03_context.py delete mode 100644 libs/arcade-mcp-server/docs/examples/04_secrets.md delete mode 100644 libs/arcade-mcp-server/docs/examples/04_secrets.py delete mode 100644 libs/arcade-mcp-server/docs/examples/05_logging.md delete mode 100644 libs/arcade-mcp-server/docs/examples/05_logging.py delete mode 100644 libs/arcade-mcp-server/docs/examples/06_tool_organization.md delete mode 100644 libs/arcade-mcp-server/docs/examples/06_tool_organization.py delete mode 100644 libs/arcade-mcp-server/docs/examples/07_auth.md delete mode 100644 libs/arcade-mcp-server/docs/examples/07_auth.py delete mode 100644 libs/arcade-mcp-server/docs/examples/README.md delete mode 100644 libs/arcade-mcp-server/docs/examples/tools_math.py delete mode 100644 libs/arcade-mcp-server/docs/examples/tools_text.py delete mode 100644 libs/arcade-mcp-server/docs/getting-started/quickstart.md delete mode 100644 libs/arcade-mcp-server/docs/index.md delete mode 100644 libs/arcade-mcp-server/mkdocs.yml diff --git a/.github/workflows/test-docs.yml b/.github/workflows/test-docs.yml deleted file mode 100644 index 2c85533d..00000000 --- a/.github/workflows/test-docs.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Test Docs - -on: - push: - branches: - - main - pull_request: - types: [opened, synchronize, reopened, ready_for_review] - -jobs: - test-docs: - runs-on: ubuntu-latest - steps: - - name: Check out - uses: actions/checkout@v4 - - - name: Install uv - uses: astral-sh/setup-uv@v6 - - - name: Test docs - working-directory: libs/arcade-mcp-server - run: make sync && make docs-build diff --git a/libs/arcade-mcp-server/Makefile b/libs/arcade-mcp-server/Makefile index 64e00c6e..8dff77d9 100644 --- a/libs/arcade-mcp-server/Makefile +++ b/libs/arcade-mcp-server/Makefile @@ -25,16 +25,3 @@ mypy: ## Run mypy .PHONY: test test: ## Run tests uv run pytest --cov=arcade_mcp_server --cov-report=term-missing ../tests/arcade_mcp_server - -.PHONY: docs -docs: ## Build docs - uv run mkdocs build - uv run mkdocs serve - -.PHONY: docs-serve -docs-serve: ## Serve docs locally - uv run mkdocs serve - -.PHONY: docs-build -docs-build: ## Build docs - uv run mkdocs build diff --git a/libs/arcade-mcp-server/docs/advanced/sharing-servers.md b/libs/arcade-mcp-server/docs/advanced/sharing-servers.md deleted file mode 100644 index d5bbb5d2..00000000 --- a/libs/arcade-mcp-server/docs/advanced/sharing-servers.md +++ /dev/null @@ -1,180 +0,0 @@ -# Sharing Your MCP Server - -Make your MCP server accessible to others by exposing it through a secure tunnel and registering it with Arcade. This allows remote users and services to interact with your tools without deploying to a cloud platform. - -## Overview - -By default, your MCP server runs locally on `localhost:8000`. To share it: -1. Run your server with HTTP transport -2. Create a secure tunnel to expose it publicly -3. Register your server in Arcade -4. Share the tools with others - -## Step 1: Run Your Server - -First, start your MCP server with HTTP transport: - -```bash -# Navigate to your server directory -cd my_server - -# Run with HTTP transport (default) -uv run server.py -uv run server.py http -``` - -Your server will start on `http://localhost:8000`. Keep this terminal running. - -## Step 2: Create a Secure Tunnel - -Open a **separate terminal** and create a tunnel using one of these options: - -### Option A: ngrok (Recommended for Getting Started) - -[ngrok](https://ngrok.com) is easy to set up and works across all platforms. - -1. **Install ngrok:** - ```bash - # macOS - brew install ngrok - - # Or download from https://ngrok.com/download - ``` - -2. **Create a tunnel:** - ```bash - ngrok http 8000 - ``` - -3. **Copy your URL:** - Look for the "Forwarding" line in the ngrok output: - ``` - Forwarding https://abc123.ngrok-free.app -> http://localhost:8000 - ``` - - Copy the `https://abc123.ngrok-free.app` URL - this is your public URL. - -**Pros:** -- Quick setup, no account required for basic use -- Automatic HTTPS -- Web dashboard to inspect requests - -**Cons:** -- Free tier URLs change on each restart -- May show interstitial page for free tier - -### Option B: Cloudflare Tunnel - -[Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/) provides persistent URLs and advanced features. - -1. **Install cloudflared:** - ```bash - # macOS - brew install cloudflare/cloudflare/cloudflared - - # Or download from https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/ - ``` - -2. **Create a tunnel:** - ```bash - cloudflared tunnel --url http://localhost:8000 - ``` - -3. **Copy your URL:** - Look for the "Your quick Tunnel has been created" message with your URL. - -**Pros:** -- Free tier includes persistent URLs (with setup) -- Built-in DDoS protection -- Access control features - -**Cons:** -- Requires Cloudflare account for persistent URLs -- More complex setup for advanced features - -### Option C: Tailscale Funnel - -[Tailscale Funnel](https://tailscale.com/kb/1223/tailscale-funnel) is ideal for sharing within a team or organization. - -1. **Install Tailscale:** - ```bash - # macOS - brew install tailscale - - # Or download from https://tailscale.com/download - ``` - -2. **Authenticate:** - ```bash - tailscale up - ``` - -3. **Create a funnel:** - ```bash - tailscale funnel 8000 - ``` - -4. **Get your URL:** - Tailscale will display your funnel URL (e.g., `https://my-machine.tail-scale.ts.net`) - -**Pros:** -- Persistent URLs tied to your machine -- Private by default (only shared with specified users) -- No bandwidth limits - -**Cons:** -- Requires Tailscale account -- Best for team/organization use cases - -## Step 3: Register Your MCP Server in Arcade - -Once you have a public URL, register your MCP server in the Arcade dashboard to make it accessible through the Arcade API. - -### Register Your Server - -1. **Navigate to the MCP Servers page** in your [Arcade dashboard](https://api.arcade.dev/dashboard/servers) - -2. **Click "Add Server"** - -3. **Fill in the registration form:** - - **ID**: Choose a unique identifier (e.g., `my-mcp-server`) - - **Server Type**: Select "HTTP/SSE" - - **URL**: Enter your public tunnel URL from Step 2 with `/mcp` appended - - Example: `https://abc123.ngrok-free.app/mcp` - - Example: `https://my-tunnel.trycloudflare.com/mcp` - - Example: `https://my-machine.tail-scale.ts.net/mcp` - - **Secret**: Enter a secret for your server (or use `dev` for testing) - - **Timeout**: Configure request timeout (default: 30s) - - **Retry**: Configure retry attempts (default: 3) - -4. **Click "Create"** - -### Configuration Example - -```yaml -ID: my-mcp-server -Server Type: HTTP/SSE -URL: https://abc123.ngrok-free.app -Secret: my-secure-secret-123 -Timeout: 30s -Retry: 3 -``` - -## Step 4: Test Your MCP Server - -Verify that your server is accessible and working correctly. - -### Using the Arcade Playground - -1. **Go to the [Arcade Playground](https://api.arcade.dev/dashboard/playground/chat)** - -2. **Select your MCP server** from the dropdown - -3. **Choose a tool** from your server - -4. **Execute the tool** with test parameters - -5. **Verify the response:** - - Check that the response is correct - - View request logs in your local server terminal - - Inspect the tunnel dashboard for request details diff --git a/libs/arcade-mcp-server/docs/advanced/transports.md b/libs/arcade-mcp-server/docs/advanced/transports.md deleted file mode 100644 index f097bcf3..00000000 --- a/libs/arcade-mcp-server/docs/advanced/transports.md +++ /dev/null @@ -1,213 +0,0 @@ -# Transport Modes - -MCP servers can communicate with clients through different transport mechanisms. Each transport is optimized for specific use cases and client types. - -## stdio Transport - -The stdio (standard input/output) transport is used for direct client connections. - -### Characteristics -- Communicates via standard input/output streams -- Logs go to stderr to avoid interfering with protocol messages -- Ideal for desktop applications and command-line tools -- Used by Claude Desktop and similar clients - -### Usage - -**Recommended: Using Arcade CLI** - -```bash -# Run with stdio transport -uv run server.py stdio -``` - -**Alternative: Direct Python** - -```bash -# Run your server directly -uv run server.py stdio - -# Or with python -app.run(transport="stdio") -``` - -### Client Configuration - -For Claude Desktop, use the `arcade configure` command: - -```bash -arcade configure claude --from-local -``` - -Or manually edit `~/Library/Application Support/Claude/claude_desktop_config.json`: - -```json -{ - "mcpServers": { - "my-tools": { - "command": "arcade", - "args": ["mcp", "stdio"], - "cwd": "/path/to/your/tools" - } - } -} -``` - -## HTTP Transport - -The HTTP transport provides REST/SSE endpoints for web-based clients. - -### Characteristics -- RESTful API with Server-Sent Events (SSE) for streaming -- Supports hot reload for development -- Includes health checks and API documentation -- Can be deployed behind reverse proxies -- Suitable for web applications and services - -### Usage - -**Recommended: Using Arcade CLI** - -```bash -# Run with HTTP transport (default) -uv run server.py -uv run server.py http -``` - -**Alternative: Direct Python** - -```bash -# Run your server directly -uv run server.py - -# Or with python -app.run(transport="http", host="0.0.0.0", port=8080) -``` - -### Endpoints - -When running in HTTP mode, the server provides: - -- `GET /health` - Health check endpoint -- `GET /mcp` - SSE endpoint for MCP protocol -- `GET /docs` - Swagger UI documentation (debug mode) -- `GET /redoc` - ReDoc documentation (debug mode) - -### Development Features - -**With Arcade CLI:** - -```python -# Enable hot reload and debug mode -app.run(host="127.0.0.1", port=8000, reload=True) - -# This enables: -# - Automatic restart on code changes -# - Detailed error messages -# - API documentation endpoints -# - Verbose logging -``` - -## Choosing a Transport - -### Use stdio when: -- Integrating with desktop applications (Claude Desktop, VS Code) -- Building command-line tools -- You need simple, direct communication -- Running in environments without network access - -### Use HTTP when: -- Building web applications -- Deploying to cloud environments -- You need to support multiple concurrent clients -- Integrating with existing web services -- You want API documentation and testing tools - -## Transport Configuration - -### Environment Variables - -Both transports respect common environment variables: - -```bash -# Server identification -MCP_SERVER_NAME="My MCP Server" -MCP_SERVER_VERSION="1.0.0" - -# Logging -MCP_DEBUG=true -MCP_LOG_LEVEL=DEBUG - -# HTTP-specific -MCP_HTTP_HOST=0.0.0.0 -MCP_HTTP_PORT=8080 -``` - -### Programmatic Configuration - -When using MCPApp: - -```python -from arcade_mcp_server import MCPApp - -app = MCPApp( - name="my-server", - version="1.0.0", - log_level="DEBUG" -) - -# Run with specific transport -if __name__ == "__main__": - import sys - - if len(sys.argv) > 1 and sys.argv[1] == "stdio": - app.run(transport="stdio") - else: - app.run(transport="http", host="0.0.0.0", port=8080) -``` - -## Security Considerations - -### stdio Transport -- Inherits security context of the parent process -- No network exposure -- Suitable for trusted environments - -### HTTP Transport -- Exposes network endpoints -- Should use authentication in production -- Consider using HTTPS with reverse proxy -- Implement rate limiting for public deployments - -## Advanced Transport Features - -### Custom Middleware (HTTP) - -Add custom middleware to HTTP transports: - -```python -from arcade_mcp_server import MCPApp - -app = MCPApp(name="my-server") - -# Add custom middleware -@app.middleware("http") -async def add_custom_headers(request, call_next): - response = await call_next(request) - response.headers["X-Custom-Header"] = "value" - return response -``` - -### Transport Events - -Listen to transport lifecycle events: - -```python -@app.on_event("startup") -async def startup_handler(): - print("Server starting up...") - -@app.on_event("shutdown") -async def shutdown_handler(): - print("Server shutting down...") -``` diff --git a/libs/arcade-mcp-server/docs/api/mcp_app.md b/libs/arcade-mcp-server/docs/api/mcp_app.md deleted file mode 100644 index 848497f9..00000000 --- a/libs/arcade-mcp-server/docs/api/mcp_app.md +++ /dev/null @@ -1,47 +0,0 @@ -### MCPApp - -A FastAPI-like interface for building MCP servers with lazy initialization. - -MCPApp provides a clean, minimal API for building MCP servers programmatically. It handles tool collection, server configuration, and transport setup with a developer-friendly interface. - -#### Basic Usage - -```python -from arcade_mcp_server import MCPApp - -app = MCPApp(name="my_server", version="1.0.0") - -@app.tool -def greet(name: str) -> str: - return f"Hello, {name}!" - -app.run(host="127.0.0.1", port=8000) -``` - -#### Class Reference - -::: arcade_mcp_server.mcp_app.MCPApp - -#### Examples - -```python -# --- server.py --- -# Programmatic server creation with a simple tool and HTTP transport - -from arcade_mcp_server import MCPApp - -app = MCPApp(name="example_server", version="1.0.0") - -@app.tool -def echo(text: str) -> str: - return f"Echo: {text}" - -if __name__ == "__main__": - # Start an HTTP server (good for local development/testing) - app.run(host="0.0.0.0", port=8000, reload=False, debug=True) -``` - -```bash -# then run the server -python server.py -``` diff --git a/libs/arcade-mcp-server/docs/api/server/errors.md b/libs/arcade-mcp-server/docs/api/server/errors.md deleted file mode 100644 index b6c78666..00000000 --- a/libs/arcade-mcp-server/docs/api/server/errors.md +++ /dev/null @@ -1,36 +0,0 @@ -### Exceptions - -Domain-specific error types raised by the MCP server and components. - -::: arcade_mcp_server.exceptions - -#### Examples - -```python -from arcade_mcp_server.exceptions import ( - MCPError, - NotFoundError, - DuplicateError, - ValidationError, - ToolError, -) - -# Raising a not-found when a resource is missing -async def read_resource_or_fail(uri: str) -> str: - if not await exists(uri): - raise NotFoundError(f"Resource not found: {uri}") - return await read(uri) - -# Validating input -def validate_age(age: int) -> None: - if age < 0: - raise ValidationError("age must be non-negative") - -# Handling tool execution errors in middleware or handlers -async def call_tool_safely(call): - try: - return await call() - except ToolError as e: - # Convert to an error result or re-raise - raise MCPError(f"Tool failed: {e}") -``` diff --git a/libs/arcade-mcp-server/docs/api/server/middleware.md b/libs/arcade-mcp-server/docs/api/server/middleware.md deleted file mode 100644 index aa7ca327..00000000 --- a/libs/arcade-mcp-server/docs/api/server/middleware.md +++ /dev/null @@ -1,50 +0,0 @@ -### Middleware - -Base interfaces and built-in middleware. - -::: arcade_mcp_server.middleware.base.Middleware - -::: arcade_mcp_server.middleware.base.MiddlewareContext - -::: arcade_mcp_server.middleware.base.compose_middleware - -#### Built-ins - -::: arcade_mcp_server.middleware.logging.LoggingMiddleware - -::: arcade_mcp_server.middleware.error_handling.ErrorHandlingMiddleware - -#### Examples - -```python -# Implement a custom middleware -from arcade_mcp_server.middleware.base import Middleware, MiddlewareContext - -class TimingMiddleware(Middleware): - async def __call__(self, context: MiddlewareContext, call_next): - import time - start = time.perf_counter() - try: - return await call_next(context) - finally: - elapsed_ms = (time.perf_counter() - start) * 1000 - # Attach timing info to context metadata - context.metadata["elapsed_ms"] = round(elapsed_ms, 2) -``` - -```python -# Compose middleware and create a server -from arcade_mcp_server.middleware.base import compose_middleware -from arcade_mcp_server.middleware.logging import LoggingMiddleware -from arcade_mcp_server.middleware.error_handling import ErrorHandlingMiddleware -from arcade_mcp_server.server import MCPServer -from arcade_core.catalog import ToolCatalog - -middleware = compose_middleware([ - ErrorHandlingMiddleware(mask_error_details=False), - LoggingMiddleware(log_level="INFO"), - TimingMiddleware(), -]) - -server = MCPServer(catalog=ToolCatalog(), middleware=[middleware]) -``` diff --git a/libs/arcade-mcp-server/docs/api/server/server.md b/libs/arcade-mcp-server/docs/api/server/server.md deleted file mode 100644 index d293a930..00000000 --- a/libs/arcade-mcp-server/docs/api/server/server.md +++ /dev/null @@ -1,53 +0,0 @@ - - -# Server - -### Low-level Server - -Low-level server for hosting Arcade tools over MCP. - -::: arcade_mcp_server.server.MCPServer - -#### Examples - -```python -# Basic server with tool catalog and stdio transport -import asyncio -from arcade_mcp_server.server import MCPServer -from arcade_core.catalog import ToolCatalog -from arcade_mcp_server.transports.stdio import StdioTransport - -async def main(): - catalog = ToolCatalog() - server = MCPServer(catalog=catalog, name="example", version="1.0.0") - await server._start() - try: - # Run stdio transport loop - transport = StdioTransport() - await transport.run(server) - finally: - await server._stop() - -if __name__ == "__main__": - asyncio.run(main()) -``` - -```python -# Handling a single HTTP streamable connection -import asyncio -from arcade_mcp_server.server import MCPServer -from arcade_core.catalog import ToolCatalog -from arcade_mcp_server.transports.http_streamable import HTTPStreamableTransport - -async def run_http(): - catalog = ToolCatalog() - server = MCPServer(catalog=catalog) - await server._start() - try: - transport = HTTPStreamableTransport(host="0.0.0.0", port=8000) - await transport.run(server) - finally: - await server._stop() - -asyncio.run(run_http()) -``` diff --git a/libs/arcade-mcp-server/docs/api/server/settings.md b/libs/arcade-mcp-server/docs/api/server/settings.md deleted file mode 100644 index 5d7b828c..00000000 --- a/libs/arcade-mcp-server/docs/api/server/settings.md +++ /dev/null @@ -1,49 +0,0 @@ -### Settings - -Global configuration and environment-driven settings. - -::: arcade_mcp_server.settings.MCPSettings - -#### Sub-settings - -::: arcade_mcp_server.settings.ServerSettings - -::: arcade_mcp_server.settings.MiddlewareSettings - -::: arcade_mcp_server.settings.NotificationSettings - -::: arcade_mcp_server.settings.TransportSettings - -::: arcade_mcp_server.settings.ArcadeSettings - -::: arcade_mcp_server.settings.ToolEnvironmentSettings - -#### Examples - -```python -from arcade_mcp_server.settings import MCPSettings - -settings = MCPSettings( - debug=True, - middleware=MCPSettings.middleware.__class__( - enable_logging=True, - mask_error_details=False, - ), - server=MCPSettings.server.__class__( - title="My MCP Server", - instructions="Use responsibly", - ), - transport=MCPSettings.transport.__class__( - http_host="0.0.0.0", - http_port=8000, - ), -) -``` - -```python -# Loading from environment -from arcade_mcp_server.settings import MCPSettings - -# Values like ARCADE_MCP_DEBUG, ARCADE_MCP_HTTP_PORT, etc. are parsed -settings = MCPSettings() -``` diff --git a/libs/arcade-mcp-server/docs/api/server/types.md b/libs/arcade-mcp-server/docs/api/server/types.md deleted file mode 100644 index 1d442826..00000000 --- a/libs/arcade-mcp-server/docs/api/server/types.md +++ /dev/null @@ -1,37 +0,0 @@ -### Types - -Core Pydantic models and enums for the MCP protocol shapes. - -::: arcade_mcp_server.types - -#### Examples - -```python -# Constructing a JSON-RPC request and response model -from arcade_mcp_server.types import JSONRPCRequest, JSONRPCResponse - -req = JSONRPCRequest(id=1, method="ping", params={}) -res = JSONRPCResponse(id=req.id, result={}) -print(req.model_dump_json()) -print(res.model_dump_json()) -``` - -```python -# Building a tools/call request and examining result shape -from arcade_mcp_server.types import CallToolRequest, CallToolResult, TextContent - -call = CallToolRequest( - id=2, - method="tools/call", - params={ - "name": "Toolkit.tool", - "arguments": {"text": "hello"}, - }, -) -# Result would typically be produced by the server: -result = CallToolResult( - content=[TextContent(type="text", text="Echo: hello")], - structuredContent={"result": "Echo: hello"}, - isError=False -) -``` diff --git a/libs/arcade-mcp-server/docs/clients/claude.md b/libs/arcade-mcp-server/docs/clients/claude.md deleted file mode 100644 index 4929b817231fa1d6afff94e6a3eacba98ece1923..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6557 zcmcIoOLHPe685>zd)z}Bg~JjnV7=bG=&)fV5i{D6M%n?5!(mTA(Op1WO;@|B8Vx%k z|8{?w)eQ(S9;_W-cy!kzA75sEnFn;1sWQ=YuHBtCMHD^$Pp&KqW4)uRvm0{SF0^&z zXV#R{8Krn0n|zW^ORIcpa&k-O^}J1kS?Xw7ra1XN%`%$lte~YSafGK*ep>3{wt1QzAUfnGH45ED7{^sw0d-P(Yo7MW94Si0bK<3YK!re<$`vL3t{QZYUMR4%JqHa zH99l}yGUinlupDKiOIkAG*b&rCfBso{wNA+%f9(?7#tqO39bL|@s-b?s0Ou5hm%Zc zDKoLks>|zRYp`gF1MFI@i8b?6!z6_0 zFsR)A*_nJK$9v+>)Fn0=Teg>2p za>xTdAEJkV*Jksz@%p6Mq>Cp}#d@u?M4ei6LetEQ8QRAZhq1~fYS8b z`DfdpHD?n9D-L0hD&jwbT^JAlXwy}h`LuvWmFuGD2UG#pxQ<-tT(4Q9!tJB@6oFoj zTmQfFVS<(%)2gZh>mN?v0EW&N8xRAMUR(@b-kuHz*ROi788VEN)=H>5od>uuSQxAi z0b&i8q4fM&Qp@4LCv^X^d-iI0dOg^ZyO!#sV#lRJQvM8be>~K}6$m(nUevHRw%d)^y%Z!U(fdOxf%s*1FAr_qNnqaNo?5?4L6MP)*Nz zYmY?HEl7hRSLisMprlj`4leUts-afxywBjDRbpS@+|D@7J0bn8)IvJ^V-=$I!!E=g zfLV{rDP5UFM^P_l;87xvGBcfmmJo;mc@S!b>&zIYDxX2k{ge{Oi8y=UY?ppCK(Nwz z>SBY|U`f|PG7)y{@h)gwYxORQ`2U*LCDkT`A>tj?G4OyAqzw@qDxk4@l|TXL^P+N3 z79cWqRzmH}P6yOqAvkmwQFLikvI*^q4pen!A3s-hXdTykk(=#gv##jka#m+ovD@Wh z_z@jk)q)`P-UQv?dEs2i1qH~4r-g|UxF7YsvK+Kg#Qb-r(Io~#D}5XqO|&EEX{v4{0x5c{Z8}-j z&EJUM0{v2oZn}e)Xw|F`!bu6c%6?R;s#P2jQWhG9qv+cdcaY<;;M&I$85gTJ|u_w1}noYFb$etj|nhUto{DmA;`*?{4Z0cCI$~w8B zbk0Kz($*S`FKS!MHdeiMD)Q3|xuUZu6T0rN*;jDcM8%qsI6!3#&H>8-7{LJqeDDRTCg+0GV^0+T>|Z+NQPK^2 zK8+cmkha-mp7ge2MH>W4TK@}YFlAtJQRqC;dCap1<`!DTvyCAe>(y*x3c}N`zK*TN z6c67(LAK;U0AI2RbcqncK~5GErc>A|G@F%hY>sBLqBeo;0Fz8@__XuVvI7#m(3vT! zU61$GH#w{}U3xRhlQC1Z>jN<6< z4U*d&*Csl_tZ;xfexfi3UC#oi$PR)e{dlgoYfdNQD;)$7l(>3&#>2ez9B$vCT)n$S z`0m*orh2=WK!!2T|Ut-gctDe(?oyYa~BpENlgiuI=CZ=r4FHqPB}=5RHpW z7>JJQ7b7{jkV$bQ!@R&gHfA7o(cmp%iC;=?u8K)FU*$lF#@$QIP|7J~3gord6jTgL^oSAE$#$sy7$F%W679dPZo71H6QfHYt zrVsq~;mgM6?HHHFCCAC3Y|-ywdnxEog}Gu@vR(i>B=W3fo@7R$b~JzrjAt6}R$`vj zmw?uS%+GYi=r>N=7Fwg+9j-5f@QvYcT&5TeXsi49KizS{j5!|atJ%;9vB7~&&?6~?3FSa9< diff --git a/libs/arcade-mcp-server/docs/clients/cursor.md b/libs/arcade-mcp-server/docs/clients/cursor.md deleted file mode 100644 index f9ada09d007d81f628c5679e4437600f14b61699..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8263 zcmc&(OLH5!5#Gvi&N=3QP+Mi2Ym$B>7gZ@`TB29lwJnuIIpuP>NN5Hmu^!Hh2N=n; zOaDDzH-LFavaQ5Qq60-@@aX=~kFR^S#BNoZyc7p}lPL1vwGlEC2?()SU?Jutz;JC#6+E|G%waFvm%y-JkzPRTA5)KZEcC85@LOn${x&M0ejwghl*fl&;o!^}1|28fq=wOnmS(c@vz@Wihb zrw7p!jJA&u3!SRy=}`PLFFzP)rRt+t?B~+xSYU^$px;~Kl>$78c)U%6ED~)?ryUk5 zyLROL`R+Oy?b`u%MY?#t$RYUbhTZoXd2Ea3@-yXwK(U)Ky* zD~wHaUQZ`jfV^kn-A&@Tw+h;*>IGi~oV z;Uc{j(R@Dt!@x$qK;#}I8hW4UZ3`O0pf@g7tRBU9>~zCW&#BgX$P0MM(qQ~uZ?Nt? z3_Fm%^ov#Qy{{+77YXh0^OuWY6fg2LQRQW`pUTc#C*y#lx6}Q@*GJ>&{#TZINiO+6 zeO^YFq-zJYr`s(<3nkU$9t36_~>Bv`{b=d6|ir2$1i)|0#@v`Vj|h{BF!%x;`_N3$B36Q3GV#@ z{wHIr&s8Usa=ew5&DXHdSd_fxRtO^?-yOPxfjgND_HF?FL6d!>OIyiQOtN!b<{71( zC^|I?F)EmrDO9W%01Y#EF77YPy%mCCqi@;hbvGTIg?{!%f&#pEs}5G6Fga) zJF4Z)K(`zGem$7(pFW>W4}YJ$ZXC5edeu!`tnDSz$}?%yUF&g+SUyV5X3nhYxPMKr zz43JXe0(yQogTkz^lFcOMK4+C|A$IA*6VbWg^B}DEy2LV3uKh4Bqm6#<{(RT<_-7M zfY>=tW_)0wl>5_7oo8Zj6p)WKxxBYl=V;NEct#weqA1|lB5yHVmP%QXftl>|5QfvF zhpETPz+)W!l|=zI1QuN4=tM0jgv8328Cl4E`gp(uN3>4p8qe@!rOJ&kAJd)Q$>il^ zcPjeg#qr@QlBP5+O%&3YCh1Pe5%;u-b8zxa6ur^lR`OixRGz_&o%Tqsj;O#bYnJDT zhB%TbGO+^py@BN&IhHrw6pH!Xws@(H<=_Bmz~@d>3S3?4b{vPOkx{^|D}%cuCv6^A z1Ur)@(5aX}auFqIKXStElVXBDNEsmEI6E#cQA9y0T(@Q4O?CWXE?^%#pDxUhsEiDd zuq#Km3z?~u!~!WjchyITbY3#Ds!0>=2PYvFG^~aWZ=zp^1{zU7aQNfDl`Z(fz&+a0 z=?6(62Sms*pgMtq;SfKDbi^$}OhXqhRw{D=#HqR6QteXg?1+2VG8Aw3oULB^80oZv zKM*N(4ETq+?#*iP8F#D~?OB0TM~r@tH^JCDj)*mU@NkvV)DtU9%jNY6m*&l#SvW4uFeuH_X82l>A-eTb z;AtX|v^u>23WSyQD`{iIIg+WtTASynsFx^SGrDG5R?3BNxB9x=Q&q>3`hfpfVluIi z@x{+ybXHV$+cSX6TPafK8&;{uJ8;3(gjvq3yjCN6bB zHbnO^rAX$t;FRLs1)IHZmsERHgDk0dr4>kYJmA7D`&7G=a?gPC(|lEa!>%3;VOh?u zy5Wj0v#TkEPLkFgN(RhQG+NaiC-+4|V`=}J;QAwp0vXx6_N3LfeaMy?qARc>6?dYGf*_Qxhh;6HYOt?Z)p+qH&+FC(iHeqlPRb>AiQn6~gv< z;hB@e^C@qVnC}i5VqVaN`6`wIo{0EbzmMI|scF2M5?|hHLL+0mPhDi+S3@R2Mzm=5 z@zpx=M`W(w-^U;fcT$#lX~eHE6}70+l$(3U=yjGE_oFc;6wMK!fkYim^tW)gFLREq zt&8RODG;L+*R>Y8jQnMl=hP;R{!S}7YaL{ zTa^qDdfn)?TD{hvJ=bJ|dnrF}#7neua2QE-;0$M_(> z1`*W{ny1j^Rn2HxR&@z#UDbCpSrksYmwa4o*`>{qe{Kl)Qx0RcGPR+R|O7v7?byEcloI^3i2>2 zW7u}sW_I~lLel%QdxYJbZ4$c>vy5_13scw_Zj8yI_b<7iIM(3-BF3v2a+6vd zQkkZpt|BjJy~k-w#LX9wKA9Pgc6c@9^>EpeNd!}w6RUiP?EueS2Qc}SQAeakl-k2` z7t*+fWAmh3i>qUa*h8J=R)!>|lFxHq!A*jNMpU6d&~e*6mj-}{Gdxl}Q5Ll{0vm5m z*6R}_y&Is^iP9P6AiY}IN8u0WmxAID+|6ayd=XMPd4vp+jj(a=YPdHG@m;yw@B2o1 zGXcTh@eBAC1yu^9_y-12&l%A`heqJ{jZC7Rc#f7qqIhAL$aTh$UtIX@7{tz;^`=hl zv=wF5V&j?25dCFNX-%ky74j>yuQvW0ox-`kPPp;42~O+)GNSP6 z7WUrLzE^07<2x^SXAmYqE4wVjJ>v(CiLe{FG=q?gJn8yNT_#czrP&cA>yTcX7}u5~ z3FxnMyn!Dl)w(eE3rR~J`W<(k;6*Uz)hLkuNPX$%vzn1R)c{a3m{D%J&c==?V?lkt z?neDR4I9(e29Xqr6m3S+g@B););MynK)Iv&5pOd75LL)ap`(3#A;L+4TO}???Xv5TW3- diff --git a/libs/arcade-mcp-server/docs/clients/inspector.md b/libs/arcade-mcp-server/docs/clients/inspector.md deleted file mode 100644 index ce000540..00000000 --- a/libs/arcade-mcp-server/docs/clients/inspector.md +++ /dev/null @@ -1,363 +0,0 @@ -# MCP Inspector - -The MCP Inspector is a powerful debugging and testing tool for MCP servers. It provides a web-based interface to interact with your Arcade MCP server, test tools, and monitor protocol messages. - -## Installation - -Install the MCP Inspector globally: - -```bash -npm install -g @modelcontextprotocol/inspector -``` - -Or use npx to run without installing: - -```bash -npx @modelcontextprotocol/inspector -``` - -## Basic Usage - -### Connecting to HTTP Servers - -For MCP servers running over HTTP: - -```bash -# Start your MCP server -uv run server.py - -# In another terminal, start the inspector -mcp-inspector http://localhost:8000/mcp -``` - -### Connecting to stdio Servers - -For stdio-based servers: - -```bash -# Start the inspector with your server command -mcp-inspector "uv run server.py stdio" - -# With additional project directory -mcp-inspector --cwd /path/to/project "uv run server.py stdio" -``` - -## Inspector Features - -### Tool Explorer - -The Tool Explorer shows all available tools with: - -- Tool names and descriptions -- Parameter schemas -- Return type information -- Example invocations - -### Interactive Testing - -Test tools directly from the interface: - -1. Select a tool from the explorer -2. Fill in parameter values -3. Click "Execute" to run the tool -4. View results and execution time - -### Protocol Monitor - -Monitor all MCP protocol messages: - -- Request/response pairs -- Message timing -- Protocol errors -- Raw JSON data - -### Resource Browser - -If your server provides resources: - -- Browse available resources -- View resource contents -- Test resource operations - -### Prompt Templates - -Test prompt templates if supported: - -- View available prompts -- Fill template parameters -- Preview rendered prompts - -## Advanced Usage - -### Custom Environment - -Pass environment variables to your server: - -```bash -# Using env command -env ARCADE_API_KEY=your-key mcp-inspector "uv run server.py stdio" - -# Using inspector's env option -mcp-inspector --env ARCADE_API_KEY=your-key "uv run server.py stdio" -``` - -### Working Directory - -Set the working directory for your server: - -```bash -mcp-inspector --cwd /path/to/project "uv run server.py stdio" -``` - -### Debug Mode - -Enable verbose logging: - -```bash -# Debug the inspector -mcp-inspector --debug "uv run server.py stdio" - -# Server debug logging is configured in your server.py -# app = MCPApp(name="my_server", version="1.0.0", log_level="DEBUG") -``` - -## Testing Workflows - -### Tool Development - -1. **Configure your server with hot reload**: - ```python - # In your server.py - if __name__ == "__main__": - transport = sys.argv[1] if len(sys.argv) > 1 else "http" - app.run(transport=transport, host="127.0.0.1", port=8000, reload=True) - ``` - - Then run: - ```bash - uv run server.py - ``` - -2. **Connect the inspector**: - ```bash - mcp-inspector http://localhost:8000/mcp - ``` - -3. **Develop and test**: - - Modify your tool code - - Server auto-reloads - - Test immediately in inspector - -### Performance Testing - -Use the inspector to measure tool performance: - -1. Enable timing in the Protocol Monitor -2. Execute tools multiple times -3. Analyze response times -4. Identify bottlenecks - -### Error Debugging - -Debug tool errors effectively: - -1. Enable debug mode on your server -2. Execute the failing tool -3. Check Protocol Monitor for error details -4. View server logs in terminal - -## Integration Testing - -### Test Suites - -Create test suites using the inspector: - -```javascript -// test-tools.js -const tests = [ - { - tool: "greet", - params: { name: "World" }, - expected: "Hello, World!" - }, - { - tool: "calculate", - params: { expression: "2 + 2" }, - expected: 4 - } -]; - -// Run tests via inspector API -``` - -### Automated Testing - -Combine with testing frameworks: - -```python -# test_mcp_tools.py -import subprocess -import json -import pytest - -def test_tool_via_inspector(): - # Start server - server = subprocess.Popen( - ["python", "-m", "arcade_mcp_server"], - stdout=subprocess.PIPE - ) - - # Use inspector's API to test tools - # ... -``` - -## Best Practices - -### Development Setup - -1. **Use Split Terminal**: - - Terminal 1: MCP server with reload - - Terminal 2: Inspector - - Terminal 3: Code editor - -2. **Enable All Debugging**: - ```python - # In server.py - app = MCPApp(name="my_server", version="1.0.0", log_level="DEBUG") - - # Run with reload - app.run(transport="http", host="127.0.0.1", port=8000, reload=True) - ``` - - Then run with environment file: - ```bash - uv run server.py - ``` - -3. **Save Test Cases**: - - Export successful tool calls - - Build regression test suite - - Document edge cases - -### Production Testing - -1. **Test Against Production Config**: - ```bash - mcp-inspector "uv run server.py stdio" - ``` - -2. **Verify Security**: - - Test with limited permissions - - Verify API key handling - - Check error messages don't leak secrets - -3. **Load Testing**: - - Execute tools rapidly - - Monitor memory usage - - Check for resource leaks - -## Troubleshooting - -### Connection Issues - -#### "Failed to connect" - -1. Verify server is running -2. Check correct URL/command -3. Ensure ports aren't blocked -4. Try with `--debug` flag - -#### "Protocol error" - -1. Ensure server implements MCP correctly -2. Check for version compatibility -3. Review server logs -4. Verify transport type - -### Tool Issues - -#### "Tool not found" - -1. Verify tool is decorated with `@tool` -2. Check tool discovery in server -3. Ensure no import errors -4. Restart server and inspector - -#### "Parameter validation failed" - -1. Check parameter types match schema -2. Verify required parameters -3. Test with simpler values -4. Review tool documentation - -## Examples - -### Quick Test Session - -```bash -# 1. Start a simple MCP server -cat > test_tools.py << 'EOF' -from arcade_mcp_server import tool -from typing import Annotated - -@tool -def echo(message: Annotated[str, "Message to echo"]) -> str: - """Echo the message back.""" - return message - -@tool -def add( - a: Annotated[int, "First number"], - b: Annotated[int, "Second number"] -) -> Annotated[int, "Sum"]: - """Add two numbers.""" - return a + b -EOF - -# 2. Start inspector -mcp-inspector "uv run server.py stdio" - -# 3. Test tools in the web interface -``` - -### HTTP Server Testing - -```bash -# 1. Create an MCPApp server -cat > app.py << 'EOF' -from arcade_mcp_server import MCPApp -from typing import Annotated - -app = MCPApp(name="test-server", version="1.0.0") - -@app.tool -def get_time() -> Annotated[str, "Current time"]: - """Get the current time.""" - from datetime import datetime - return datetime.now().isoformat() - -if __name__ == "__main__": - app.run(port=9000, reload=True) -EOF - -# 2. Run the server -python app.py - -# 3. Connect inspector -mcp-inspector http://localhost:9000/mcp -``` - -### Debugging Session - -```bash -# 1. Enable all debugging -export DEBUG=* -export MCP_DEBUG=true - -# 2. Start server with verbose logging -# (configure log_level="DEBUG" in your server.py) -uv run server.py stdio 2>server.log - -# 3. Start inspector with debugging -mcp-inspector --debug "uv run server.py stdio" -``` diff --git a/libs/arcade-mcp-server/docs/clients/vscode.md b/libs/arcade-mcp-server/docs/clients/vscode.md deleted file mode 100644 index a05ccd7d..00000000 --- a/libs/arcade-mcp-server/docs/clients/vscode.md +++ /dev/null @@ -1,485 +0,0 @@ -# Visual Studio Code - -While VSCode doesn't have native MCP support yet, you can integrate Arcade MCP servers with VSCode through extensions and custom configurations. This guide shows various integration approaches. - -## Prerequisites - -- Visual Studio Code installed -- Python 3.10+ installed -- `arcade-mcp` package installed (`pip install arcade-mcp`) -- Python extension for VSCode - -## Integration Methods - -### Method 1: Terminal Integration - -Use VSCode's integrated terminal to run MCP servers: - -1. Open integrated terminal (`Ctrl/Cmd + ` `) -2. Start your MCP server: - ```bash - uv run server.py - ``` -3. Use split terminals for multiple servers - -### Method 2: Task Runner - -Create tasks to manage MCP servers: - -#### Create `.vscode/tasks.json`: - -```json -{ - "version": "2.0.0", - "tasks": [ - { - "label": "Start MCP Server", - "type": "shell", - "command": "python", - "args": ["-m", "arcade_mcp_server", "--reload", "--debug"], - "isBackground": true, - "problemMatcher": { - "pattern": { - "regexp": "^(ERROR|WARNING):\\s+(.+)$", - "severity": 1, - "message": 2 - }, - "background": { - "activeOnStart": true, - "beginsPattern": "^Starting.*", - "endsPattern": "^.*Server ready.*" - } - }, - "presentation": { - "reveal": "always", - "panel": "dedicated" - } - }, - { - "label": "Start MCP (HTTP)", - "type": "shell", - "command": "python", - "args": [ - "-m", "arcade_mcp_server", - "--host", "0.0.0.0", - "--port", "8000", - "--reload" - ], - "isBackground": true, - "problemMatcher": [] - }, - { - "label": "Test Tools", - "type": "shell", - "command": "python", - "args": ["${workspaceFolder}/test_tools.py"], - "problemMatcher": "$python" - } - ] -} -``` - -Run tasks via: -- Command Palette: `Tasks: Run Task` -- Terminal menu: `Terminal > Run Task` - -### Method 3: Launch Configurations - -Debug your MCP tools with VSCode's debugger: - -#### Create `.vscode/launch.json`: - -```json -{ - "version": "0.2.0", - "configurations": [ - { - "name": "Debug MCP Server", - "type": "python", - "request": "launch", - "module": "arcade_mcp_server", - "args": ["--debug", "--reload"], - "cwd": "${workspaceFolder}", - "env": { - "PYTHONPATH": "${workspaceFolder}", - "ARCADE_API_KEY": "${env:ARCADE_API_KEY}" - }, - "console": "integratedTerminal" - }, - { - "name": "Debug Specific Tool", - "type": "python", - "request": "launch", - "program": "${workspaceFolder}/tools/my_tool.py", - "args": ["--test"], - "cwd": "${workspaceFolder}", - "console": "integratedTerminal" - }, - { - "name": "Debug with Package", - "type": "python", - "request": "launch", - "module": "arcade_mcp_server", - "args": [ - "--tool-package", "github", - "--debug" - ], - "env": { - "GITHUB_TOKEN": "${input:githubToken}" - } - } - ], - "inputs": [ - { - "id": "githubToken", - "type": "promptString", - "description": "Enter your GitHub token", - "password": true - } - ] -} -``` - -## Development Workflow - -### Project Setup - -Recommended project structure: - -``` -my-mcp-project/ -├── .vscode/ -│ ├── launch.json # Debug configurations -│ ├── tasks.json # Task definitions -│ ├── settings.json # Workspace settings -│ └── extensions.json # Recommended extensions -├── .env # Environment variables -├── .env.example -├── tools/ -│ ├── __init__.py -│ └── my_tools.py -├── tests/ -│ └── test_tools.py -├── requirements.txt -└── pyproject.toml -``` - -### Workspace Settings - -Configure `.vscode/settings.json`: - -```json -{ - "python.defaultInterpreterPath": "${workspaceFolder}/venv/bin/python", - "python.terminal.activateEnvironment": true, - "python.linting.enabled": true, - "python.linting.pylintEnabled": true, - "python.formatting.provider": "black", - "python.testing.pytestEnabled": true, - "python.testing.pytestArgs": ["tests"], - "files.exclude": { - "**/__pycache__": true, - "**/*.pyc": true - }, - "terminal.integrated.env.linux": { - "PYTHONPATH": "${workspaceFolder}" - }, - "terminal.integrated.env.osx": { - "PYTHONPATH": "${workspaceFolder}" - }, - "terminal.integrated.env.windows": { - "PYTHONPATH": "${workspaceFolder}" - } -} -``` - -### Recommended Extensions - -Create `.vscode/extensions.json`: - -```json -{ - "recommendations": [ - "ms-python.python", - "ms-python.vscode-pylance", - "ms-vscode.live-server", - "humao.rest-client", - "redhat.vscode-yaml", - "ms-azuretools.vscode-docker" - ] -} -``` - -## Testing Tools - -### REST Client Extension - -Test HTTP MCP servers using REST Client: - -Create `test-mcp.http`: - -```http -### Get Server Info -GET http://localhost:8000/health - -### List Tools -POST http://localhost:8000/catalog -Content-Type: application/json -Authorization: Bearer {{$env ARCADE_API_KEY}} - -{} - -### Call Tool -POST http://localhost:8000/call_tool -Content-Type: application/json -Authorization: Bearer {{$env ARCADE_API_KEY}} - -{ - "tool_name": "greet", - "tool_arguments": { - "name": "World" - } -} -``` - -### Python Test Scripts - -Create test scripts for your tools: - -```python -# test_tools.py -import asyncio -from arcade_core.catalog import ToolCatalog - -async def test_tools(): - # Import your tools - from tools import my_tools - - # Create catalog - catalog = ToolCatalog() - catalog.add_tool(my_tools.greet, "test") - - # Test tool - result = await catalog.call_tool( - "test.greet", - {"name": "Test"} - ) - print(f"Result: {result}") - -if __name__ == "__main__": - asyncio.run(test_tools()) -``` - -## Debugging Tips - -### Breakpoint Debugging - -1. Set breakpoints in your tool code -2. Launch debugger with "Debug MCP Server" -3. Trigger tool execution -4. Step through code execution - -### Logging Configuration - -Enhanced logging for debugging: - -```python -# tools/__init__.py -import logging -from loguru import logger - -# Configure loguru -logger.add( - "debug.log", - rotation="10 MB", - level="DEBUG", - format="{time} {level} {message}" -) - -# Intercept standard logging -class InterceptHandler(logging.Handler): - def emit(self, record): - logger_opt = logger.opt(depth=6, exception=record.exc_info) - logger_opt.log(record.levelname, record.getMessage()) - -logging.basicConfig(handlers=[InterceptHandler()], level=0) -``` - -### Performance Profiling - -Profile your tools: - -```json -{ - "name": "Profile MCP Server", - "type": "python", - "request": "launch", - "module": "cProfile", - "args": [ - "-o", "profile.stats", - "-m", "arcade_mcp_server", - "--debug" - ], - "cwd": "${workspaceFolder}" -} -``` - -## Snippets - -Create useful code snippets in `.vscode/python.code-snippets`: - -```json -{ - "Arcade Tool": { - "prefix": "atool", - "body": [ - "from arcade_tdk import tool", - "from typing import Annotated", - "", - "@tool", - "def ${1:tool_name}(", - " ${2:param}: Annotated[${3:str}, \"${4:Parameter description}\"]", - ") -> Annotated[${5:str}, \"${6:Return description}\"]:", - " \"\"\"${7:Tool description}.\"\"\"", - " ${8:# Implementation}", - " return ${9:result}" - ], - "description": "Create an Arcade tool" - }, - "Async Tool": { - "prefix": "atoolasync", - "body": [ - "from arcade_tdk import tool", - "from typing import Annotated", - "", - "@tool", - "async def ${1:tool_name}(", - " ${2:param}: Annotated[${3:str}, \"${4:Parameter description}\"]", - ") -> Annotated[${5:str}, \"${6:Return description}\"]:", - " \"\"\"${7:Tool description}.\"\"\"", - " ${8:# Async implementation}", - " return ${9:result}" - ], - "description": "Create an async Arcade tool" - } -} -``` - -## Integration Examples - -### Multi-Server Setup - -Run multiple MCP servers for different purposes: - -```json -{ - "version": "2.0.0", - "tasks": [ - { - "label": "Start All Servers", - "dependsOn": [ - "Start API Tools", - "Start Data Tools", - "Start Utility Tools" - ], - "problemMatcher": [] - }, - { - "label": "Start API Tools", - "type": "shell", - "command": "uv run server.py", - "options": { - "cwd": "${workspaceFolder}/api_tools" - }, - "isBackground": true - }, - { - "label": "Start Data Tools", - "type": "shell", - "command": "uv run server.py", - "options": { - "cwd": "${workspaceFolder}/data_tools" - }, - "isBackground": true - }, - { - "label": "Start Utility Tools", - "type": "shell", - "command": "uv run server.py", - "options": { - "cwd": "${workspaceFolder}/util_tools" - }, - "isBackground": true - } - ] -} -``` - -### Environment Management - -Handle multiple environments: - -```json -{ - "version": "2.0.0", - "tasks": [ - { - "label": "MCP Server (Dev)", - "type": "shell", - "command": "uv run --env-file .env.dev server.py", - "problemMatcher": [] - }, - { - "label": "MCP Server (Staging)", - "type": "shell", - "command": "uv run --env-file .env.staging server.py", - "problemMatcher": [] - }, - { - "label": "MCP Server (Prod)", - "type": "shell", - "command": "uv run --env-file .env.prod server.py", - "problemMatcher": [], - "presentation": { - "reveal": "always", - "panel": "dedicated", - "showReuseMessage": true, - "clear": true - } - } - ] -} -``` - -## Best Practices - -1. **Use Virtual Environments**: Always work in isolated environments -2. **Version Control Settings**: Include `.vscode` in your repository -3. **Environment Files**: Use `.env` files for secrets -4. **Consistent Formatting**: Configure formatters and linters -5. **Test Automation**: Set up test tasks and debug configs -6. **Documentation**: Keep README and docstrings updated -7. **Git Hooks**: Use pre-commit for code quality - -## Troubleshooting - -### Common Issues - -1. **Python interpreter not found**: - - Select interpreter: `Cmd/Ctrl + Shift + P` > "Python: Select Interpreter" - - Ensure virtual environment is activated - -2. **Module import errors**: - - Check PYTHONPATH in settings - - Verify package installation - - Restart VSCode - -3. **Debug breakpoints not working**: - - Ensure you're using the debug configuration - - Check that debugpy is installed - - Verify source maps are correct - -4. **Task execution fails**: - - Check task definition syntax - - Verify working directory - - Review terminal output for errors diff --git a/libs/arcade-mcp-server/docs/examples/00_hello_world.md b/libs/arcade-mcp-server/docs/examples/00_hello_world.md deleted file mode 100644 index e432dc64..00000000 --- a/libs/arcade-mcp-server/docs/examples/00_hello_world.md +++ /dev/null @@ -1,22 +0,0 @@ -# 00 - Hello World - -The simplest possible MCP server with a single tool using arcade-mcp-server. - -## Running the Example - -- **Run (HTTP default)**: `uv run 00_hello_world.py` -- **Run (stdio for Claude Desktop)**: `uv run 00_hello_world.py stdio` - -## Source Code - -```python ---8<-- "docs/examples/00_hello_world.py" -``` - -## Key Concepts - -- **Minimal Setup**: Create `MCPApp`, define tools with `@app.tool`, and run with `app.run()` -- **Direct Execution**: Run your server file directly with `uv run` or `python` -- **Transport Flexibility**: Works with both stdio (for Claude Desktop) and HTTP -- **Type Annotations**: Use `Annotated` to provide descriptions for parameters and return values -- **Command Line Args**: Pass transport type as command line argument diff --git a/libs/arcade-mcp-server/docs/examples/00_hello_world.py b/libs/arcade-mcp-server/docs/examples/00_hello_world.py deleted file mode 100644 index 64b0a59e..00000000 --- a/libs/arcade-mcp-server/docs/examples/00_hello_world.py +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python3 -""" -00_hello_world.py - The simplest possible MCP server - -This example shows the absolute minimum code needed to create an MCP server -with a single tool using arcade-mcp-server with direct Python execution. - -To run: - uv run 00_hello_world.py # HTTP transport (default) - uv run 00_hello_world.py stdio # stdio transport for Claude Desktop -""" - -import sys -from typing import Annotated - -from arcade_mcp_server import MCPApp - -# Create the MCP application -app = MCPApp( - name="hello_world", version="1.0.0", instructions="A simple MCP server with a greeting tool" -) - - -@app.tool -def greet(name: Annotated[str, "Name of the person to greet"]) -> Annotated[str, "Welcome message"]: - """Greet a person by name with a welcome message.""" - return f"Hello, {name}! Welcome to Arcade MCP." - - -if __name__ == "__main__": - # Check if stdio transport was requested - transport = "stdio" if len(sys.argv) > 1 and sys.argv[1] == "stdio" else "http" - - print(f"Starting {app.name} v{app.version}") - print(f"Transport: {transport}") - - # Run the server - app.run(transport=transport, host="127.0.0.1", port=8000) diff --git a/libs/arcade-mcp-server/docs/examples/01_tools.md b/libs/arcade-mcp-server/docs/examples/01_tools.md deleted file mode 100644 index fabf73e6..00000000 --- a/libs/arcade-mcp-server/docs/examples/01_tools.md +++ /dev/null @@ -1,131 +0,0 @@ -# 01 - Tools - -Learn how to create tools with different parameter types and how arcade_mcp_server discovers them automatically. - -## Running the Example - -- **Run (HTTP default)**: `uv run 01_tools.py` -- **Run (stdio for Claude Desktop)**: `uv run 01_tools.py stdio` - -## Source Code - -```python ---8<-- "docs/examples/01_tools.py" -``` - -## Creating Tools - -### 1. Simple Tools - -Basic tools with simple parameter types: - -```python -@app.tool -def hello(name: Annotated[str, "Name to greet"]) -> str: - """Say hello to someone.""" - return f"Hello, {name}!" - -@app.tool -def add( - a: Annotated[float, "First number"], - b: Annotated[float, "Second number"] -) -> Annotated[float, "Sum of the numbers"]: - """Add two numbers together.""" - return a + b -``` - -### 2. List Parameters - -Working with lists of values: - -```python -@app.tool -def calculate_average( - numbers: Annotated[list[float], "List of numbers to average"] -) -> Annotated[float, "Average of all numbers"]: - """Calculate the average of a list of numbers.""" - if not numbers: - return 0.0 - return sum(numbers) / len(numbers) -``` - -### 3. Complex Types with TypedDict - -Using TypedDict for structured input and output: - -```python -class PersonInfo(TypedDict): - name: str - age: int - email: str - is_active: bool - -@tool -def create_user_profile( - person: Annotated[PersonInfo, "Person's information"] -) -> Annotated[str, "Formatted user profile"]: - """Create a formatted user profile from person information.""" - # Implementation here -``` - -## Managing Tools in MCPApp - -With the direct Python approach, you have full control over your tools: - -### 1. Defining Tools Directily -Use `@app.tool` to define tools directly on your MCPApp instance: -```python -@app.tool -def my_tool(param: str) -> str: - """Tool description.""" - return f"Processed: {param}" -``` - -### 2. Importing Tools from Files -You can import tools from other files and add them explicitly: -```python -from my_tools import calculate, process_data - -# Add imported tools to the app -app.add_tool(calculate) -app.add_tool(process_data) -``` - -### 3. Project Organization - -Example project structure: -``` -my_project/ -├── server.py # Main MCPApp -├── tools/ -│ ├── math.py # Tools using @tool decorator -│ └── utils.py # More tools -└── pyproject.toml # Dependencies -``` - -This approach gives you explicit control over which tools are loaded and how they're organized. - -## Best Practices - -### Parameter Annotations -- **Always use `Annotated`**: Provide descriptions for all parameters -- **Clear descriptions**: Help the AI understand what each parameter does -- **Type hints**: Use proper Python type hints for validation - -### Tool Design -- **Single purpose**: Each tool should do one thing well -- **Error handling**: Add validation and helpful error messages -- **Return types**: Always annotate return types with descriptions - -### Organization -- **Group related tools**: Use directories to organize by functionality -- **Naming conventions**: Use clear, descriptive names -- **Documentation**: Write clear docstrings for each tool - -## Key Concepts - -- **Explicit Control**: Use `@app.tool` decorators and `app.add_tool()` for precise tool management -- **Type Safety**: Full type annotation support with runtime validation -- **TypedDict Support**: Use TypedDict for complex structured data -- **Import Flexibility**: Import tools from your own files and external packages -- **Direct Execution**: Run servers directly with `uv run` for better development experience diff --git a/libs/arcade-mcp-server/docs/examples/01_tools.py b/libs/arcade-mcp-server/docs/examples/01_tools.py deleted file mode 100644 index acafa25d..00000000 --- a/libs/arcade-mcp-server/docs/examples/01_tools.py +++ /dev/null @@ -1,130 +0,0 @@ -#!/usr/bin/env python3 -""" -01_tools.py - Tool creation and parameter types - -This example demonstrates: -1. How to create tools with @app.tool decorator in MCPApp -2. Different parameter types (simple, lists, TypedDict) -3. Direct Python execution for better control - -To run: - uv run 01_tools.py # HTTP transport (default) - uv run 01_tools.py stdio # stdio transport for Claude Desktop -""" - -import sys -from typing import Annotated - -from arcade_mcp_server import MCPApp -from typing_extensions import TypedDict - -# Create the MCP application -app = MCPApp( - name="tools_example", - version="1.0.0", - instructions="Example server demonstrating various tool parameter types", -) - -# === SIMPLE TOOLS === - - -@app.tool -def hello(name: Annotated[str, "Name to greet"]) -> Annotated[str, "Greeting message"]: - """Say hello to someone.""" - return f"Hello, {name}!" - - -@app.tool -def add( - a: Annotated[float, "First number"], b: Annotated[float, "Second number"] -) -> Annotated[float, "Sum of the numbers"]: - """Add two numbers together.""" - return a + b - - -# === TOOLS WITH LIST PARAMETERS === - - -@app.tool -def calculate_average( - numbers: Annotated[list[float], "List of numbers to average"], -) -> Annotated[float, "Average of all numbers"]: - """Calculate the average of a list of numbers.""" - if not numbers: - return 0.0 - return sum(numbers) / len(numbers) - - -@app.tool -def factorial(n: Annotated[int, "Non-negative integer"]) -> Annotated[int, "Factorial of n"]: - """Calculate the factorial of a number.""" - if n < 0: - raise ValueError("Factorial not defined for negative numbers") - if n == 0: - return 1 - - result = 1 - for i in range(1, n + 1): - result *= i - return result - - -# === TOOLS WITH COMPLEX TYPES (TypedDict) === - - -class PersonInfo(TypedDict): - name: str - age: int - email: str - is_active: bool - - -@app.tool -def create_user_profile( - person: Annotated[PersonInfo, "Person's information"], -) -> Annotated[str, "Formatted user profile"]: - """Create a formatted user profile from person information.""" - status = "Active" if person["is_active"] else "Inactive" - return f""" -User Profile: -- Name: {person["name"]} -- Age: {person["age"]} -- Email: {person["email"]} -- Status: {status} -""".strip() - - -class CalculationResult(TypedDict): - sum: float - average: float - min: float - max: float - count: int - - -@app.tool -def analyze_numbers( - values: Annotated[list[float], "List of numbers to analyze"], -) -> Annotated[CalculationResult, "Statistical analysis of the numbers"]: - """Analyze a list of numbers and return statistics.""" - if not values: - return {"sum": 0.0, "average": 0.0, "min": 0.0, "max": 0.0, "count": 0} - - return { - "sum": sum(values), - "average": sum(values) / len(values), - "min": min(values), - "max": max(values), - "count": len(values), - } - - -if __name__ == "__main__": - # Check if stdio transport was requested - transport = "stdio" if len(sys.argv) > 1 and sys.argv[1] == "stdio" else "http" - - print(f"Starting {app.name} v{app.version}") - print(f"Transport: {transport}") - - # Run the server - app.run(transport=transport, host="127.0.0.1", port=8000) diff --git a/libs/arcade-mcp-server/docs/examples/02_building_apps.md b/libs/arcade-mcp-server/docs/examples/02_building_apps.md deleted file mode 100644 index e1715767..00000000 --- a/libs/arcade-mcp-server/docs/examples/02_building_apps.md +++ /dev/null @@ -1,116 +0,0 @@ -# 02 - Building Apps - -Build and run an MCP server programmatically using the FastAPI-like `MCPApp` interface. - -## Running the Example - -- **Run HTTP**: `python examples/02_building_apps.py` -- **Run stdio**: `python examples/02_building_apps.py stdio` - -## Source Code - -```python ---8<-- "docs/examples/02_building_apps.py" -``` - -## MCPApp Features - -### 1. Creating an App - -```python -from arcade_mcp_server import MCPApp - -app = MCPApp( - name="my_server", - version="1.0.0", - title="My MCP Server", - instructions="This server provides utility tools", - log_level="INFO" -) -``` - -### 2. Adding Tools - -#### Method 1: Direct Tool Definition -Use the `@app.tool` decorator to define tools directly: -```python -@app.tool -def my_tool(param: Annotated[str, "Description"]) -> str: - """Tool description.""" - return f"Result: {param}" -``` - -#### Method 2: Importing Tools from Files -Import tools from other files and add them explicitly: -```python -from my_tools import calculate, process_data - -# Add imported tools to the app -app.add_tool(calculate) -app.add_tool(process_data) -``` - -#### Method 3: Importing from Packages -Import tools from Arcade packages: -```python -from arcade_gmail.tools import list_emails - -# Add package tools to the app -app.add_tool(list_emails) -``` - -This approach gives you explicit control over which tools are loaded and allows for modular organization. - -**For a comprehensive example of tool organization, see [06_tool_organization.md](06_tool_organization.md).** - -### 3. Running the Server - -```python -# Default HTTP transport -app.run() - -# Specify options -app.run( - host="0.0.0.0", - port=8080, - reload=True, # Auto-reload on code changes - transport="http" -) - -# For stdio transport (Claude Desktop) -app.run(transport="stdio") -``` - -### 4. Using Context - -Tools can access runtime context: -```python -@app.tool -async def context_aware(context: Context, value: str) -> dict: - """Tool that uses context features.""" - # Access user info - user_id = context.user_id - - - # Use MCP features if available - if context: - await context.log.info(f"Processing for user: {user_id}") - - # Access secrets - secret_keys = list(context.secrets.keys()) - - - return { - "user": user_id, - "value": value, - "available_secrets": secret_keys - } -``` - -## Key Concepts - -- **FastAPI-like Interface**: Familiar decorator-based API design -- **Programmatic Control**: Build servers without CLI dependency -- **Transport Flexibility**: Support for both HTTP and stdio transports -- **Context Integration**: Access to user info, logging, and secrets -- **Development Features**: Hot reload, debug logging, and more diff --git a/libs/arcade-mcp-server/docs/examples/02_building_apps.py b/libs/arcade-mcp-server/docs/examples/02_building_apps.py deleted file mode 100644 index aecba549..00000000 --- a/libs/arcade-mcp-server/docs/examples/02_building_apps.py +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env python -""" -02_building_apps.py - Build an MCP server using MCPApp - -This example shows how to build and run an MCP server programmatically -using `MCPApp` instead of relying on the arcade_mcp_server CLI. - -To run (HTTP transport by default): - python 02_building_apps.py - -To run with stdio transport (for Claude Desktop): - python 02_building_apps.py stdio -""" - -import sys -from typing import Annotated - -from arcade_mcp_server import Context, MCPApp - -# Create the MCP application -app = MCPApp( - name="my_mcp_server", version="0.1.0", instructions="Example MCP server built with MCPApp" -) - - -@app.tool -def greet( - name: Annotated[str, "Name of the person to greet"], -) -> Annotated[str, "Greeting message"]: - """Return a friendly greeting. - - Parameters: - name: Person's name - - Returns: - Greeting message. - """ - return f"Hello, {name}!" - - -@app.tool -async def whoami(context: Context) -> Annotated[dict, "Basic server and user information"]: - """Return basic information from the tool context. - - Returns: - Dictionary with `user_id` and whether MCP features are available. - """ - user_id = context.user_id or "anonymous" - - if context: - await context.log.info(f"whoami called by: {user_id}") - - secret_keys = [secret.key for secret in context.secrets] if context.secrets else [] - return { - "user_id": user_id, - "secret_keys": secret_keys, - } - - -if __name__ == "__main__": - # Check if stdio transport was requested - if len(sys.argv) > 1 and sys.argv[1] == "stdio": - app.run(transport="stdio") - else: - # Default to HTTP transport - app.run(host="127.0.0.1", port=8000) diff --git a/libs/arcade-mcp-server/docs/examples/03_context.md b/libs/arcade-mcp-server/docs/examples/03_context.md deleted file mode 100644 index 8a0747f0..00000000 --- a/libs/arcade-mcp-server/docs/examples/03_context.md +++ /dev/null @@ -1,64 +0,0 @@ -# 03 - Tool Context - -Access runtime features through Context including logging, secrets, and progress reporting. - -## Running the Example - -- **Run**: `uv run 03_context.py` -- **Run (stdio)**: `uv run 03_context.py stdio` -- **Env**: set `API_KEY`, `DATABASE_URL` - -## Source Code - -```python ---8<-- "docs/examples/03_context.py" -``` - -## Context Features - -The Context provides access to runtime features: - -### 1. Logging -Send log messages at different levels: -```python -await context.log.debug("Debug message") -await context.log.info("Information message") -await context.log.warning("Warning message") -await context.log.error("Error message") -``` - -### 2. Secrets Management -Access environment variables securely: -```python -try: - api_key = context.get_secret("API_KEY") -except ValueError: - # Handle missing secret -``` - -### 3. User Context -Access information about the current user: -```python -user_id = context.user_id or "anonymous" -``` - -### 4. Progress Reporting -Report progress for long-running operations: -```python -await context.progress.report(current, total, "Processing...") -``` - -### 5. Tool Decorator Options -Specify required secrets: -```python -@tool(requires_secrets=["DATABASE_URL", "API_KEY"]) -async def my_tool(context: Context, ...): -``` - -## Key Concepts - -- **Context Parameter**: Tools receive a `Context` as their first parameter -- **Async Functions**: Use `async def` for tools that use context features -- **Secure Secrets**: Secrets are accessed through context, not hardcoded -- **Structured Logging**: Log at appropriate levels for debugging -- **Progress Updates**: Keep users informed during long operations diff --git a/libs/arcade-mcp-server/docs/examples/03_context.py b/libs/arcade-mcp-server/docs/examples/03_context.py deleted file mode 100644 index ebbae677..00000000 --- a/libs/arcade-mcp-server/docs/examples/03_context.py +++ /dev/null @@ -1,155 +0,0 @@ -#!/usr/bin/env python3 -""" -03_context.py - Using Context with namespaced runtime APIs - -This example shows how tools can access runtime features through -Context (provided at runtime by the TDK wrapper), including logging, -secrets, and progress reporting. - -To run: - uv run 03_context.py # HTTP transport (default) - uv run 03_context.py stdio # stdio transport for Claude Desktop - -Set environment variables for secrets: - export API_KEY="your-secret-key" - export DATABASE_URL="postgresql://localhost/mydb" -""" - -import sys -from typing import Annotated, Any - -from arcade_mcp_server import Context, MCPApp - -# Create the MCP application -app = MCPApp( - name="context_example", - version="1.0.0", - instructions="Example server demonstrating Context usage", -) - - -@app.tool -async def secure_api_call( - context: Context, - endpoint: Annotated[str, "API endpoint to call"], - method: Annotated[str, "HTTP method (GET, POST, etc.)"] = "GET", -) -> Annotated[str, "API response or error message"]: - """Make a secure API call using secrets from context.""" - - # Access secrets from environment via Context helper - try: - api_key = context.get_secret("API_KEY") - except ValueError: - await context.log.error("API_KEY not found in environment") - return "Error: API_KEY not configured" - - # Log the API call - await context.log.info(f"Making {method} request to {endpoint}") - - # Simulate API call (in real code, use httpx or aiohttp) - return f"Successfully called {endpoint} with API key: {api_key[:4]}..." - - -# Don't forget to add the secret to the .env file or export it as an environment variable -@app.tool(requires_secrets=["DATABASE_URL"]) -async def database_info( - context: Context, table_name: Annotated[str | None, "Specific table to check"] = None -) -> Annotated[str, "Database connection info"]: - """Get database connection information from context.""" - - # Get database URL from secrets - try: - db_url = context.get_secret("DATABASE_URL") - except ValueError: - db_url = "Not configured" - - # Log at different levels - if db_url == "Not configured": - await context.log.warning("DATABASE_URL not set") - else: - await context.log.debug(f"Checking database: {db_url.split('@')[-1]}") - - # Get user info - user_info = f"User: {context.user_id or 'anonymous'}" - - if table_name: - return f"{user_info}\nDatabase: {db_url}\nChecking table: {table_name}" - else: - return f"{user_info}\nDatabase: {db_url}" - - -@app.tool -async def debug_context( - context: Context, - show_secrets: Annotated[bool, "Whether to show secret keys (not values)"] = False, -) -> Annotated[dict, "Current context information"]: - """Debug tool to inspect the current context.""" - - info: dict[str, Any] = { - "user_id": context.user_id, - } - - if show_secrets: - # Only show keys, not values for security - info["secret_keys"] = [s.key for s in (context.secrets or [])] - - # Log that debug info was accessed - await context.log.info(f"Debug context accessed by {context.user_id or 'unknown'}") - - return info - - -@app.tool -async def process_with_progress( - context: Context, - items: Annotated[list[str], "Items to process"], - delay_seconds: Annotated[float, "Delay between items"] = 0.1, -) -> Annotated[dict, "Processing results"]: - """Process items with progress notifications.""" - - results: dict[str, list] = {"processed": [], "errors": []} - - # Log start - await context.log.info(f"Starting to process {len(items)} items") - - for i, item in enumerate(items): - try: - # Simulate processing - import asyncio - - await asyncio.sleep(delay_seconds) - - # Report progress (current, total, message) - await context.progress.report(i + 1, len(items), f"Processing: {item}") - await context.log.debug(f"Processing item {i + 1}/{len(items)}: {item}") - - results["processed"].append(item.upper()) - - except Exception as e: - await context.log.error(f"Failed to process {item}: {e}") - results["errors"].append({"item": item, "error": str(e)}) - - # Log completion - await context.log.info( - f"Processing complete: {len(results['processed'])} succeeded, " - f"{len(results['errors'])} failed" - ) - - return results - - -# The Context provides at runtime (via TDK wrapper): -# - context.user_id: ID of the user making the request -# - context.get_secret(key): Retrieve a secret value (raises if missing) -# - context.log.(msg): Send log messages to the client (debug/info/warning/error) -# - context.progress.report(progress, total=None, message=None): Progress updates - -if __name__ == "__main__": - # Check if stdio transport was requested - transport = "stdio" if len(sys.argv) > 1 and sys.argv[1] == "stdio" else "http" - - print(f"Starting {app.name} v{app.version}") - print(f"Transport: {transport}") - - # Run the server - app.run(transport=transport, host="127.0.0.1", port=8000) diff --git a/libs/arcade-mcp-server/docs/examples/04_secrets.md b/libs/arcade-mcp-server/docs/examples/04_secrets.md deleted file mode 100644 index 32074333..00000000 --- a/libs/arcade-mcp-server/docs/examples/04_secrets.md +++ /dev/null @@ -1,59 +0,0 @@ -# 04 - Tool Secrets - -Read secrets from environment and `.env` files securely via Context. - -## Running the Example - -- **Run**: `uv run 04_secrets.py` -- **Run (stdio)**: `uv run 04_secrets.py stdio` -- **Create `.env`**: Add `API_KEY=supersecret` to a `.env` file - -## Source Code - -```python ---8<-- "docs/examples/04_secrets.py" -``` - -## Working with Secrets - -### 1. Environment Variables - -Secrets can be provided via environment variables: -```bash -export API_KEY="your-secret-key" -export DATABASE_URL="postgresql://localhost/mydb" -``` - -### 2. Using .env Files - -Create a `.env` file in the directoryof your server: -``` -API_KEY=supersecret -DATABASE_URL=postgresql://user:pass@localhost/db -GITHUB_TOKEN=ghp_xxxxxxxxxxxx -``` - -### 3. Declaring Required Secrets - -Use the `requires_secrets` parameter to declare which secrets your tool needs: -```python -@tool(requires_secrets=["API_KEY", "DATABASE_URL"]) -def my_secure_tool(context: Context) -> str: - api_key = context.get_secret("API_KEY") - db_url = context.get_secret("DATABASE_URL") -``` - -### 4. Security Best Practices - -- **Never log secret values**: Always mask or truncate when displaying -- **Declare requirements**: Use `requires_secrets` to document dependencies -- **Handle missing secrets**: Use try/except when accessing secrets -- **Use descriptive names**: Make it clear what each secret is for - -## Key Concepts - -- **Secure Access**: Secrets are accessed through context, not imported directly -- **Environment Integration**: Works with both environment variables and .env files -- **Error Handling**: Always handle the case where a secret might be missing -- **Masking**: Never expose full secret values in logs or return values -- **Declaration**: Use `requires_secrets` to make dependencies explicit diff --git a/libs/arcade-mcp-server/docs/examples/04_secrets.py b/libs/arcade-mcp-server/docs/examples/04_secrets.py deleted file mode 100644 index 17610b5f..00000000 --- a/libs/arcade-mcp-server/docs/examples/04_secrets.py +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env python3 -"""04: Read secrets from .env via Context - -Run: - uv run 04_secrets.py # HTTP transport (default) - uv run 04_secrets.py stdio # stdio transport for Claude Desktop - -Environment: - # Create a .env in the working directory with: - # API_KEY=supersecret -""" - -import sys - -from arcade_mcp_server import Context, MCPApp - -# Create the MCP application -app = MCPApp( - name="secrets_example", - version="1.0.0", - instructions="Example server demonstrating secrets usage", -) - - -@app.tool( - requires_secrets=["API_KEY"], # declare we need API_KEY -) -def use_secret(context: Context) -> str: - """Read API_KEY from context and return a masked confirmation string.""" - try: - value = context.get_secret("API_KEY") - masked = value[:2] + "***" if len(value) >= 2 else "***" - return f"Got API_KEY of length {len(value)} -> {masked}" - except Exception as e: - return f"Error getting secret: {e}" - - -if __name__ == "__main__": - # Check if stdio transport was requested - transport = "stdio" if len(sys.argv) > 1 and sys.argv[1] == "stdio" else "http" - - print(f"Starting {app.name} v{app.version}") - print(f"Transport: {transport}") - - # Run the server - app.run(transport=transport, host="127.0.0.1", port=8000) diff --git a/libs/arcade-mcp-server/docs/examples/05_logging.md b/libs/arcade-mcp-server/docs/examples/05_logging.md deleted file mode 100644 index 852cab97..00000000 --- a/libs/arcade-mcp-server/docs/examples/05_logging.md +++ /dev/null @@ -1,101 +0,0 @@ -# 05 - Logging - -Demonstrates MCP logging capabilities with various levels and patterns for debugging and monitoring. - -## Running the Example - -- **Run**: `python examples/05_logging.py` -- Set `log_level="DEBUG"` in `MCPApp` to see debug logs - -## Source Code - -```python ---8<-- "docs/examples/05_logging.py" -``` - -## Logging Features - -### 1. Log Levels - -MCP supports standard log levels: -```python -await context.log.debug("Detailed debugging information") -await context.log.info("General information") -await context.log.warning("Warning messages") -await context.log.error("Error messages") -``` - -### 2. Structured Logging - -Log with context and metadata: -```python -# Include user context -await context.log.info( - f"Action performed by user: {context.user_id}" -) - -# Add operation details -await context.log.debug( - f"Processing {item_count} items with options: {options}" -) -``` - -### 3. Error Logging - -Proper error handling and logging: -```python -try: - # Operation that might fail - result = risky_operation() -except Exception as e: - # Log error with type and message - await context.log.error( - f"Operation failed: {type(e).__name__}: {str(e)}" - ) - - # Log traceback at debug level - await context.log.debug( - f"Traceback:\n{traceback.format_exc()}" - ) -``` - -### 4. Progress Logging - -Track long-running operations: -```python -for i, item in enumerate(items): - # Log progress - await context.log.debug( - f"Progress: {i+1}/{len(items)} ({(i+1)/len(items)*100:.0f}%)" - ) - - # Process item - process(item) -``` - -### 5. Batch Processing - -Log batch operations effectively: -```python -# Log batch start -await context.log.info(f"Starting batch of {count} items") - -# Log individual items at debug level -for item in items: - await context.log.debug(f"Processing: {item}") - -# Log summary -await context.log.info( - f"Batch complete: {success_count} successful, {fail_count} failed" -) -``` - -## Best Practices - -1. **Use Appropriate Levels**: Debug for details, info for general flow, warning for issues, error for failures -2. **Include Context**: Always include relevant context like user ID, operation names, counts -3. **Structure Messages**: Use consistent message formats for easier parsing -4. **Handle Errors Gracefully**: Log errors with enough detail to debug but not expose sensitive data -5. **Progress Updates**: For long operations, provide regular progress updates -6. **Batch Summaries**: For batch operations, log both individual items (debug) and summaries (info) -7. **Performance Considerations**: Be mindful of log volume in production environments diff --git a/libs/arcade-mcp-server/docs/examples/05_logging.py b/libs/arcade-mcp-server/docs/examples/05_logging.py deleted file mode 100644 index 8893371d..00000000 --- a/libs/arcade-mcp-server/docs/examples/05_logging.py +++ /dev/null @@ -1,190 +0,0 @@ -#!/usr/bin/env python -""" -05_logging.py - MCP logging capabilities - -This example demonstrates the various logging levels and patterns -available through the MCP protocol for debugging and monitoring. - -To run: - python 05_logging.py - -To see debug logs: - Set log_level="DEBUG" when creating MCPApp -""" - -import asyncio -import time -import traceback -from typing import Annotated, Optional - -from arcade_mcp_server import Context, MCPApp - -# Create the app with debug logging -app = MCPApp(name="logging_examples", version="0.1.0", log_level="DEBUG") - - -@app.tool -async def demonstrate_log_levels( - context: Context, message: Annotated[str, "Base message to log at different levels"] -) -> Annotated[dict, "Summary of logged messages"]: - """Demonstrate all MCP logging levels.""" - - # Log at each level - levels = ["debug", "info", "warning", "error"] - logged = {} - - for level in levels: - log_message = f"[{level.upper()}] {message}" - await context.log(level, log_message) - logged[level] = log_message - - return {"logged_messages": logged, "note": "Check your MCP client to see these messages"} - - -@app.tool -async def timed_operation( - context: Context, - operation_name: Annotated[str, "Name of the operation"], - duration_seconds: Annotated[float, "How long the operation takes"] = 2.0, -) -> Annotated[dict, "Operation timing details"]: - """Perform a timed operation with detailed logging.""" - - start_time = time.time() - - # Log operation start - await context.log.info( - f"Starting operation: {operation_name} (expected duration: {duration_seconds}s)" - ) - - # Simulate work with progress logging - steps = 5 - for i in range(steps): - await context.log.debug(f"Progress: step {i + 1}/{steps} ({(i + 1) / steps * 100:.0f}%)") - - await asyncio.sleep(duration_seconds / steps) - - # Calculate results - end_time = time.time() - actual_duration = end_time - start_time - - # Log completion - await context.log.info(f"Completed operation: {operation_name} in {actual_duration:.2f}s") - - return { - "operation": operation_name, - "expected_duration": duration_seconds, - "actual_duration": round(actual_duration, 2), - "start_time": start_time, - "end_time": end_time, - } - - -@app.tool -async def error_handling_example( - context: Context, - should_fail: Annotated[bool, "Whether to simulate an error"], - error_type: Annotated[str, "Type of error to simulate"] = "ValueError", -) -> Annotated[dict, "Result or error details"]: - """Demonstrate error logging and handling.""" - - try: - await context.log.debug(f"Error handling test: should_fail={should_fail}") - - if should_fail: - if error_type == "ValueError": - raise ValueError("This is a simulated value error") # noqa: TRY301 - elif error_type == "KeyError": - raise KeyError("missing_key") # noqa: TRY301 - elif error_type == "ZeroDivisionError": - result = 1 / 0 - return {"result": result} - else: - raise Exception(f"Generic error of type: {error_type}") # noqa: TRY002, TRY301 - - # Success case - await context.log.info("Operation completed successfully") - - except Exception as e: - # Log the error with details - await context.log.error(f"Operation failed with {type(e).__name__}: {e!s}") - - # Log traceback separately at debug level - await context.log.debug(f"Traceback:\n{traceback.format_exc()}") - - return { - "status": "error", - "error_type": type(e).__name__, - "error_message": str(e), - "handled": True, - } - else: - return {"status": "success", "message": "No errors occurred"} - - -@app.tool -async def structured_logging( - context: Context, - user_action: Annotated[str, "Action the user is performing"], - metadata: Annotated[dict | None, "Additional metadata to log"] = None, -) -> Annotated[str, "Confirmation message"]: - """Demonstrate structured logging patterns.""" - - # Log main action - await context.log.info( - f"User action: {user_action} (user_id: {context.user_id or 'anonymous'})" - ) - - # Log additional details at debug level - await context.log.debug( - f"Context details: {len(context.secrets) if context.secrets else 0} secrets available" - ) - - # Log metadata if provided - if metadata: - await context.log.debug(f"Custom metadata: {metadata}") - - return f"Logged user action: {user_action}" - - -@app.tool -async def batch_processing_logs( - context: Context, - items: Annotated[list[str], "Items to process"], - fail_on_item: Annotated[Optional[str], "Item that should fail"] = None, -) -> Annotated[dict, "Processing results with detailed logs"]: - """Process items with detailed logging for each step.""" - - results: dict[str, list] = {"successful": [], "failed": []} - - await context.log.info(f"Starting batch processing of {len(items)} items") - - for i, item in enumerate(items): - try: - # Log item start - await context.log.debug(f"Processing item {i + 1}/{len(items)}: {item}") - - # Simulate failure if requested - if item == fail_on_item: - raise ValueError(f"Simulated failure for item: {item}") # noqa: TRY301 - - # Simulate processing - await asyncio.sleep(0.1) - - results["successful"].append(item) - - except Exception as e: - await context.log.warning(f"Failed to process '{item}': {e!s}") - results["failed"].append({"item": item, "error": str(e)}) - - # Log summary - await context.log.info( - f"Batch processing complete: {len(results['successful'])} successful, " - f"{len(results['failed'])} failed", - ) - - return results - - -if __name__ == "__main__": - # Run the server - app.run(host="127.0.0.1", port=8000) diff --git a/libs/arcade-mcp-server/docs/examples/06_tool_organization.md b/libs/arcade-mcp-server/docs/examples/06_tool_organization.md deleted file mode 100644 index c212723a..00000000 --- a/libs/arcade-mcp-server/docs/examples/06_tool_organization.md +++ /dev/null @@ -1,191 +0,0 @@ -# 06 - Tool Organization - -This example demonstrates the power of direct Python server execution by showing how to organize tools across multiple files and packages. - -## Running the Example - -- **Run HTTP**: `uv run 06_tool_organization.py` -- **Run stdio**: `uv run 06_tool_organization.py stdio` - -## Project Structure - -The example demonstrates this recommended project structure: - -``` -my_server/ -├── .env -├── server.py # Main MCPApp -├── tools/ -│ ├── __init__.py -│ ├── math_tools.py # @tool decorated functions -│ └── text_tools.py # @tool decorated functions -├── pyproject.toml -└── README.md -``` - -## Source Code - -```python ---8<-- "docs/examples/06_tool_organization.py" -``` - -## Key Concepts - -### 1. Modular Tool Organization - -Define tools in separate files using the `@tool` decorator: - -```python -# tools/math_tools.py -from arcade_mcp_server import tool -from typing import Annotated - -@tool -def add(a: Annotated[int, "First number"], b: Annotated[int, "Second number"]) -> int: - """Add two numbers together.""" - return a + b -``` - -### 2. Importing Tools from Files - -Import tools from your local files and add them explicitly: - -```python -# server.py -from tools_math import add, multiply -from tools_text import capitalize_string, word_count - -app.add_tool(add) -app.add_tool(multiply) -app.add_tool(capitalize_string) -app.add_tool(word_count) -``` - -### 3. Importing Tools from Packages - -You can also import tools from Arcade packages: - -```python -# Import tools from other Arcade packages -from arcade_gmail.tools import list_emails -from arcade_google.tools import search_web - -app.add_tool(list_emails) -app.add_tool(search_web) -``` - -### 4. Mixed Approaches - -Combine imported tools with direct tool definitions: - -```python -# Import tools from files -from tools_math import add -app.add_tool(add) - -# Define tools directly -@app.tool -def server_info() -> dict: - """Return information about this server.""" - return {"name": "My Server", "version": "1.0.0"} -``` - -## Benefits of This Approach - -### Explicit Control -- Choose exactly which tools to include -- No auto-discovery surprises -- Clear dependency management - -### Standard Python Patterns -- Use normal Python imports -- Follow Python packaging conventions -- Leverage existing Python tools (uv, poetry, etc.) - -### Flexible Organization -- Tools can be in separate files -- Tools can be in separate packages -- Easy to test individual tools - -### Development Workflow -- Use `uv run server.py` for fast iteration -- Standard Python debugging tools work -- Easy to add CLI arguments for configuration - -## Running Your Own Organized Server - -### 1. Create Your Project Structure - -``` -my_server/ -├── .env -├── server.py -├── tools/ -│ ├── __init__.py -│ ├── email_tools.py -│ ├── file_tools.py -│ └── api_tools.py -└── pyproject.toml -``` - -### 2. Create Tool Files - -```python -# tools/email_tools.py -from arcade_mcp_server import tool - -@tool -def send_email(to: str, subject: str, body: str) -> dict: - """Send an email.""" - # Implementation here - return {"status": "sent", "to": to} -``` - -### 3. Build Your Server - -```python -# server.py -import sys -from arcade_mcp_server import MCPApp -from tools.email_tools import send_email -from tools.file_tools import read_file, write_file - -app = MCPApp(name="my_server", version="1.0.0") - -# Add imported tools -app.add_tool(send_email) -app.add_tool(read_file) -app.add_tool(write_file) - -# Add direct tools -@app.tool -def server_status() -> str: - return "Server is running" - -if __name__ == "__main__": - transport = sys.argv[1] if len(sys.argv) > 1 else "http" - app.run(transport=transport) -``` - -### 4. Run Your Server - -```bash -# Run with uv -uv run server.py - -# Run with stdio for Claude Desktop -uv run server.py stdio -``` - -## Comparison with CLI Approach - -| Feature | Direct Python | CLI Auto-discovery | -|---------|---------------|-------------------| -| Tool Selection | Explicit with `app.add_tool()` | Automatic discovery | -| File Organization | Your choice | Directory-based | -| Import Control | Full control | Limited | -| Deployment | Standard Python | Custom CLI needed | -| Testing | Standard Python tools | Mix Python + CLI | -| Debugging | Python debuggers work | Limited | - -The direct Python approach gives you full control and follows standard Python patterns, making it ideal for production servers and complex tool organization. diff --git a/libs/arcade-mcp-server/docs/examples/06_tool_organization.py b/libs/arcade-mcp-server/docs/examples/06_tool_organization.py deleted file mode 100644 index f7a22dce..00000000 --- a/libs/arcade-mcp-server/docs/examples/06_tool_organization.py +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env python3 -""" -06_tool_organization.py - Demonstrating modular tool organization - -This example showcases the power of the direct Python approach by demonstrating: -- Tools defined in separate files and imported -- Tools imported from other Arcade packages -- Mixed approaches: @app.tool decorators + imported tools -- Explicit control over which tools are added to the server - -Project Structure (recommended): - my_server/ - ├── .env - ├── server.py # Main MCPApp - ├── tools/ - │ ├── __init__.py - │ ├── math_tools.py # @tool decorated functions - │ └── text_tools.py # @tool decorated functions - ├── pyproject.toml - └── README.md - -To run (HTTP transport by default): - uv run 06_tool_organization.py - -To run with stdio transport (for Claude Desktop): - uv run 06_tool_organization.py stdio -""" - -import sys -from typing import Annotated - -from arcade_mcp_server import MCPApp - -# Import tools from our 'mock' other_files module -# In a real project, these could come from actual separate files -from tools_math import add, multiply -from tools_text import capitalize_string, word_count - -# In a real project, you could also import from Arcade PyPI packages: -# from arcade_gmail.tools import list_emails - -# Create the MCP application -app = MCPApp( - name="organized_server", - version="1.0.0", - instructions="Example server demonstrating modular tool organization", -) - -# Method 1: Add imported tools explicitly -app.add_tool(add) -app.add_tool(multiply) -app.add_tool(capitalize_string) -app.add_tool(word_count) - - -# Method 2: Define tools directly on the app -@app.tool -def server_info() -> Annotated[dict, "Information about this server"]: - """Return information about this MCP server.""" - return { - "name": "Organized Server", - "version": "1.0.0", - "description": "Demonstrates modular tool organization", - "total_tools": 6, # 4 imported + 2 defined here - } - - -@app.tool -def combine_results( - text: Annotated[str, "Text to process"], - add_num: Annotated[int, "Number to add"], - multiply_num: Annotated[int, "Number to multiply"], -) -> Annotated[dict, "Combined results from multiple tools"]: - """Demonstrate using multiple tools together.""" - return { - "original_text": text, - "capitalized": capitalize_string(text), - "word_count": word_count(text), - "math_result": multiply(add(5, add_num), multiply_num), - } - - -if __name__ == "__main__": - # Check if stdio transport was requested - transport = "stdio" if len(sys.argv) > 1 and sys.argv[1] == "stdio" else "http" - - print(f"Starting {app.name} v{app.version}") - print(f"Transport: {transport}") - print("Setting up database...") - # simulate a database setup - print("Database setup complete") - - # Run the server - app.run(transport=transport, host="127.0.0.1", port=8000) diff --git a/libs/arcade-mcp-server/docs/examples/07_auth.md b/libs/arcade-mcp-server/docs/examples/07_auth.md deleted file mode 100644 index 36c5696d..00000000 --- a/libs/arcade-mcp-server/docs/examples/07_auth.md +++ /dev/null @@ -1,123 +0,0 @@ -# 07 - OAuth Tools - -Learn how to create tools that require OAuth - -## Prerequisites - -Before running this example, you need to authenticate with Arcade: - -```bash -# Install the Arcade CLI (if not already installed) -uv pip install arcade-mcp - -# Login to Arcade -arcade login -``` - -## Running the Example - -- **Run HTTP**: `uv run examples/07_auth.py` -- **Run stdio**: `uv run examples/07_auth.py stdio` - -## Source Code - -```python ---8<-- "docs/examples/07_auth.py" -``` - -## OAuth Authentication Features - -### 1. Requiring Authentication - -Use the `requires_auth` parameter with an auth provider to require OAuth: - -```python -from arcade_mcp_server.auth import Reddit - -@app.tool(requires_auth=Reddit(scopes=["read"])) -async def get_posts_in_subreddit( - context: Context, - subreddit: Annotated[str, "The name of the subreddit"] -) -> dict: - """Get posts from a specific subreddit.""" - # OAuth token is automatically injected into context - oauth_token = context.get_auth_token_or_empty() - # Use the token to make authenticated API requests -``` - -### 2. Specifying OAuth Scopes - -Different tools may require different scopes: - -```python -# Read-only access -@app.tool(requires_auth=Reddit(scopes=["read"])) -async def read_only_tool(context: Context) -> dict: - """Tool that only reads data.""" - pass - -# Multiple scopes for more permissions -@app.tool(requires_auth=Reddit(scopes=["read", "identity"])) -async def identity_tool(context: Context) -> dict: - """Tool that accesses user identity.""" - pass -``` - -### 3. Accessing OAuth Tokens - -OAuth tokens are securely injected into the context at runtime: - -```python -# Get the token (returns empty string if not authenticated) -oauth_token = context.get_auth_token_or_empty() - -# Use token in API requests -headers = { - "Authorization": f"Bearer {oauth_token}", - "User-Agent": "my-app", -} -``` - -### 4. Making Authenticated API Requests - -Use the OAuth token with httpx or other HTTP clients: - -```python -import httpx - -async with httpx.AsyncClient() as client: - response = await client.get( - "https://oauth.reddit.com/api/endpoint", - headers={"Authorization": f"Bearer {oauth_token}"} - ) - response.raise_for_status() - return response.json() -``` - -## Available Auth Providers - -The `arcade_mcp_server.auth` module provides several OAuth providers: - -## Authentication Flow - -1. **User runs `arcade login`**: Authenticates with Arcade and stores credentials -2. **Tool is called**: MCP client calls a tool that requires authentication -3. **Authorization Required**: If the user has not authorized the required scopes, then they are prompted to go through an OAuth flow -3. **Token injection**: Arcade injects the OAuth token into the tool's context -4. **API request**: Tool uses the token to make authenticated API requests -5. **Response**: Tool returns data to the MCP client - -The LLM and MCP clients never see the OAuth tokens - they are securely injected server-side. - -## Security Best Practices - -1. **Never log tokens**: OAuth tokens should never be logged or exposed -2. **Use appropriate scopes**: Request only the scopes your tool actually needs - -## Key Concepts - -- **OAuth Integration**: Arcade handles OAuth flows and token management -- **Secure Token Injection**: Tokens are injected into context at runtime -- **Scope Management**: Specify exactly which permissions your tool needs -- **Provider Support**: Multiple OAuth providers available out of the box -- **User Privacy**: LLMs and MCP clients never see OAuth tokens diff --git a/libs/arcade-mcp-server/docs/examples/07_auth.py b/libs/arcade-mcp-server/docs/examples/07_auth.py deleted file mode 100644 index c3769744..00000000 --- a/libs/arcade-mcp-server/docs/examples/07_auth.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env python3 -""" -07_auth.py - Using tools with OAuth - -This example demonstrates how to create and use tools that require OAuth. -Tools that require auth will automatically prompt users to authorize the action when called. - -Prerequisites: - 1. Install arcade-mcp: uv pip install arcade-mcp - 2. Login to Arcade: arcade login - 3. Run this server: uv run 07_auth.py - -To run: - uv run examples/07_auth.py - uv run examples/07_auth.py stdio # For Claude Desktop -""" - -import sys -from typing import Annotated - -import httpx -from arcade_mcp_server import Context, MCPApp -from arcade_mcp_server.auth import Reddit - -# Create the app -app = MCPApp(name="auth_example", version="1.0.0", log_level="DEBUG") - - -# To use this tool, you need to use the Arcade CLI (uv pip install arcade-mcp) -# and run 'arcade login' to authenticate. -@app.tool(requires_auth=Reddit(scopes=["read"])) -async def get_posts_in_subreddit( - context: Context, subreddit: Annotated[str, "The name of the subreddit"] -) -> dict: - """Get posts from a specific subreddit""" - # Normalize the subreddit name - subreddit = subreddit.lower().replace("r/", "").replace(" ", "") - - # Prepare the httpx request - # OAuth token is injected into the context at runtime. - # LLMs and MCP clients cannot see or access your OAuth tokens. - oauth_token = context.get_auth_token_or_empty() - headers = { - "Authorization": f"Bearer {oauth_token}", - "User-Agent": "mcp_server-mcp-server", - } - params = {"limit": 5} - url = f"https://oauth.reddit.com/r/{subreddit}/hot" - - # Make the request - async with httpx.AsyncClient() as client: - response = await client.get(url, headers=headers, params=params) - response.raise_for_status() - - # Return the response - return response.json() - - -# Run with specific transport -if __name__ == "__main__": - # Get transport from command line argument, default to "http" - transport = sys.argv[1] if len(sys.argv) > 1 else "http" - - print(f"Starting auth example server with {transport} transport") - print("Prerequisites:") - print(" 1. Install: uv pip install arcade-mcp") - print(" 2. Login: arcade login") - print("") - - # Run the server - # - "http" (default): HTTP streaming for Cursor, VS Code, etc. - # - "stdio": Standard I/O for Claude Desktop, CLI tools, etc. - app.run(transport=transport, host="127.0.0.1", port=8000) diff --git a/libs/arcade-mcp-server/docs/examples/README.md b/libs/arcade-mcp-server/docs/examples/README.md deleted file mode 100644 index a06a1131..00000000 --- a/libs/arcade-mcp-server/docs/examples/README.md +++ /dev/null @@ -1,84 +0,0 @@ -# Arcade MCP Examples - -This directory contains examples demonstrating how to build MCP servers with your Arcade tools. - -## Getting Started - -The easiest way to get started is with `arcade new`: - -```bash -# Install the CLI -uv pip install arcade-mcp - -# Create a new server project with example tools -arcade new my_server -cd my_server - -# Run your server -uv run server.py -``` - -This creates a complete project with `server.py`, `pyproject.toml`, and example tools showing best practices. - -## Examples Overview - -### Basic Examples - -1. **[00_hello_world.py](00_hello_world.py)** – Minimal tool example - - Single `@tool` function showing the basics - - Run: `uv run 00_hello_world.py` (or `uv run 00_hello_world.py stdio`) - -2. **[01_tools.py](01_tools.py)** – Creating tools and discovery - - Simple parameters, lists, and `TypedDict` - - How the server discovers tools automatically - - Run: `uv run 01_tools.py` - -3. **[02_building_apps.py](02_building_apps.py)** – Building apps with MCPApp - - Create an `MCPApp`, register tools with `@app.tool` - - Run HTTP: `uv run 02_building_apps.py` - - Run stdio: `uv run 02_building_apps.py stdio` - -4. **[03_context.py](03_context.py)** – Using `Context` - - Access secrets, logging, and user context - - Run: `uv run 03_context.py` - -5. **[04_tool_secrets.py](04_secrets.py)** – Working with secrets - - Use `requires_secrets` and access masked values - - Run: `uv run 04_secrets.py` - -6. **[05_logging.py](05_logging.py)** – Logging with MCP - - Demonstrates debug/info/warning/error levels and structured logs - - Run: `uv run 05_logging.py` - -7. **[06_tool_organization.py](06_tool_organization.py)** – Tool organization and imports - - Demonstrate modular tool organization, importing from files and packages - - Run: `uv run 06_tool_organization.py` - -8. **[07_auth.py](07_auth.py)** – Tools that require auth - - Create tools that require OAuth scopes - - Use Reddit OAuth to fetch posts - - Prerequisites: Run `arcade login` to authenticate with Arcade - - Run: `uv run 07_auth.py` - -## Running Examples - -### Recommended: Direct Python Execution - -Most examples can be run directly with Python using `uv`: - -```bash -# Run any example file directly -uv run 00_hello_world.py -uv run 02_building_apps.py -uv run 06_tool_organization.py - -# With specific transport -uv run server.py stdio # For Claude Desktop -uv run server.py http # HTTP by default - -# You can also run with python directly -python 00_hello_world.py -python 02_building_apps.py stdio -``` - -All example files include proper command-line argument handling with `if __name__ == "__main__":` blocks. diff --git a/libs/arcade-mcp-server/docs/examples/tools_math.py b/libs/arcade-mcp-server/docs/examples/tools_math.py deleted file mode 100644 index 56e03ee7..00000000 --- a/libs/arcade-mcp-server/docs/examples/tools_math.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python3 -""" -tools_math.py - Mathematical tools - -This file demonstrates how to organize tools in separate files. -All functions decorated with @tool will be discoverable and can be imported. -""" - -from typing import Annotated - -from arcade_mcp_server import tool - - -@tool -def add(a: Annotated[int, "First number"], b: Annotated[int, "Second number"]) -> int: - """Add two numbers together.""" - return a + b - - -@tool -def multiply(a: Annotated[int, "First number"], b: Annotated[int, "Second number"]) -> int: - """Multiply two numbers together.""" - return a * b - - -@tool -def divide(a: Annotated[float, "Dividend"], b: Annotated[float, "Divisor"]) -> float: - """Divide two numbers.""" - if b == 0: - raise ValueError("Cannot divide by zero") - return a / b diff --git a/libs/arcade-mcp-server/docs/examples/tools_text.py b/libs/arcade-mcp-server/docs/examples/tools_text.py deleted file mode 100644 index dfd133ea..00000000 --- a/libs/arcade-mcp-server/docs/examples/tools_text.py +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env python3 -""" -tools_text.py - Text processing tools - -This file demonstrates how to organize text processing tools in separate files. -All functions decorated with @tool will be discoverable and can be imported. -""" - -from typing import Annotated - -from arcade_mcp_server import tool - - -@tool -def capitalize_string(text: Annotated[str, "Text to capitalize"]) -> str: - """Capitalize the first letter of a string.""" - return text.capitalize() - - -@tool -def word_count(text: Annotated[str, "Text to count words in"]) -> int: - """Count the number of words in a string.""" - return len(text.split()) - - -@tool -def reverse_string(text: Annotated[str, "Text to reverse"]) -> str: - """Reverse a string.""" - return text[::-1] diff --git a/libs/arcade-mcp-server/docs/getting-started/quickstart.md b/libs/arcade-mcp-server/docs/getting-started/quickstart.md deleted file mode 100644 index d80bba58..00000000 --- a/libs/arcade-mcp-server/docs/getting-started/quickstart.md +++ /dev/null @@ -1,165 +0,0 @@ -# Quick Start - -The `arcade_mcp_server` package provides powerful ways to run MCP servers with your Arcade tools. **We recommend using `arcade new`** from the `arcade-mcp` CLI to create your server project with all necessary files and dependencies. - -## Recommended: Create with arcade new - -### 1. Install the CLI - -```bash -uv pip install arcade-mcp -``` - -The `arcade-mcp` package includes the CLI tools and the `arcade-mcp-server` library. - -### 2. Create Your Server - -```bash -arcade new my_server -cd my_server -``` - -This generates a complete project with: - -- **server.py** - Main server file with MCPApp and example tools - -- **pyproject.toml** - Dependencies and project configuration - -- **.env.example** - Example `.env` file containing a secret required by one of the generated tools in `server.py` - -The generated `server.py` includes proper structure with command-line argument handling: - -```python -#!/usr/bin/env python3 -import sys -from typing import Annotated -from arcade_mcp_server import MCPApp - -app = MCPApp(name="my_server", version="1.0.0") - -@app.tool -def greet(name: Annotated[str, "Name to greet"]) -> str: - """Greet someone by name.""" - return f"Hello, {name}!" - -if __name__ == "__main__": - transport = sys.argv[1] if len(sys.argv) > 1 else "http" - app.run(transport=transport, host="127.0.0.1", port=8000) -``` - -### 3. Run Your Server - -```bash -# Run with uv (recommended) -uv run server.py - -# Run with HTTP transport (default) -uv run server.py http - -# Run with stdio transport (for Claude Desktop) -uv run server.py stdio -``` - -You should see output like: - -```text -INFO | Starting server v1.0.0 (my_server) -INFO | Added tool: greet -INFO | Added tool: add_numbers -INFO | Starting MCP server on http://127.0.0.1:8000 -``` - -For HTTP transport, view your server's API docs at [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs). - -### 4. Configure MCP Clients - -Connect your server to AI assistants: - -```bash -# Configure Claude Desktop -arcade configure claude --from-local - -# Configure Cursor IDE -arcade configure cursor --from-local - -# Configure VS Code -arcade configure vscode --from-local -``` - -That's it! Your MCP server is running and connected to your AI assistant. - - -## Building MCP Servers - -The simplest way to create an MCP server programmatically is using `MCPApp`, which provides a FastAPI-like interface: - -```python -from arcade_mcp_server import MCPApp -from typing import Annotated - -app = MCPApp( - name="my_serve_", - version="1.0.0", - instructions="Custom MCP server with specialized tools" -) - -@app.tool -def calculate( - expression: Annotated[str, "Mathematical expression to evaluate"] -) -> Annotated[float, "The result of the calculation"]: - """Safely evaluate a mathematical expression.""" - # Safe evaluation logic here - return eval(expression, {"__builtins__": {}}, {}) - -@app.tool -def fetch_data( - url: Annotated[str, "URL to fetch data from"] -) -> Annotated[dict, "The fetched data"]: - """Fetch data from an API endpoint.""" - import requests - return requests.get(url).json() - -# Run the server -if __name__ == "__main__": - app.run(host="0.0.0.0", port=8080, reload=True) -``` - - - -## Secrets - -Define your tool secrets in an environment file `.env` in the same directory as your `MCPApp`, or export as environment variables - -```bash -# Tool secrets (available to tools via context) -MY_API_KEY="secret-value" -DATABASE_URL="postgresql://..." -``` - -## Development Tips - -### Hot Reload -Use the `reload=True` parameter for development to automatically restart on code changes: - -```python -app.run(host="127.0.0.1", port=8000, reload=True) -``` - -### Logging -- Set `log_level="DEBUG"` in MCPApp for verbose logging -- In stdio mode, logs go to stderr -- In HTTP mode, logs go to stdout - -### Docs for your MCP Server -With HTTP transport, access API documentation at: - -- http://localhost:8000/docs (Swagger UI) - -- http://localhost:8000/redoc (ReDoc) - -## Next Steps - -- Check out the [Examples](../examples/README.md) for detailed tutorials -- Learn about [Client Integration](../clients/claude.md) with Claude Desktop, Cursor, and VS Code -- Explore the [MCPApp API](../api/mcp_app.md) for advanced server customization -- Read about [Transport Modes](../advanced/transports.md) (stdio vs HTTP) diff --git a/libs/arcade-mcp-server/docs/index.md b/libs/arcade-mcp-server/docs/index.md deleted file mode 100644 index cd010671..00000000 --- a/libs/arcade-mcp-server/docs/index.md +++ /dev/null @@ -1,152 +0,0 @@ -# Arcade MCP - -

- Arcade Logo -

- -Arcade MCP (Model Context Protocol) enables AI assistants and development tools to interact with your Arcade tools through a standardized protocol. Build, deploy, and integrate your MCP servers seamlessly across different AI platforms. - -## Quick Links - -- **[Quickstart Guide](getting-started/quickstart.md)** - Get up and running in minutes -- **[Walkthrough](examples/README.md)** - Learn by example -- **[API Reference](api/mcp_app.md)** - MCPApp API documentation - -## Features - -- 🚀 **FastAPI-like Interface** - Simple, intuitive API with `MCPApp` -- 🔧 **Tool Discovery** - Automatic discovery of tools in your project -- 🔌 **Multiple Transports** - Support for stdio and HTTP/SSE -- 🤖 **Multi-Client Support** - Works with Claude, Cursor, VS Code, and more -- 📦 **Package Integration** - Load installed Arcade packages -- 🔐 **Built-in Security** - Environment-based configuration and secrets -- 🔄 **Hot Reload** - Development mode with automatic reloading -- 📊 **Production Ready** - Deploy with Docker, systemd, PM2, or cloud platforms - -## Getting Started - -### Installation - -We recommend installing the `arcade-mcp-server` library for direct Python development: - -```bash -uv pip install arcade-mcp-server -``` - -Or install the `arcade-mcp` CLI package for additional tooling and streamlined development workflow: - -```bash -uv pip install arcade-mcp -``` - -### Quick Start: Create a New Server (Recommended) - -The fastest way to get started is with the `arcade new` command, which creates a complete MCP server project: - -```bash -# Install the CLI -uv pip install arcade-mcp - -# Create a new server project -arcade new my_server - -# Navigate to the project -cd my_server -``` - -This generates a complete project with: - -- **server.py** - Main server file with MCPApp and example tools - -- **pyproject.toml** - Dependencies and project configuration - -- **.env.example** - Example `.env` file containing a secret required by one of the generated tools in `server.py` - -The generated `server.py` includes proper command-line argument handling: - -```python -#!/usr/bin/env python3 -import sys -from typing import Annotated -from arcade_mcp_server import MCPApp - -app = MCPApp(name="my_server", version="1.0.0") - -@app.tool -def greet(name: Annotated[str, "Name to greet"]) -> str: - """Greet someone by name.""" - return f"Hello, {name}!" - -if __name__ == "__main__": - transport = sys.argv[1] if len(sys.argv) > 1 else "http" - app.run(transport=transport, host="127.0.0.1", port=8000) -``` - -This approach gives you: -- **Complete Project Setup** - Everything you need in one command - -- **Best Practices** - Proper dependency management with pyproject.toml - -- **Example Code** - Learn from working examples of common patterns - -- **Production Ready** - Structured for growth and deployment - -### Running Your Server - -Run your server directly with Python: - -```bash -# Run with HTTP transport (default) -uv run server.py - -# Run with stdio transport (for Claude Desktop) -uv run server.py stdio - -# Or use python directly -python server.py http -python server.py stdio -``` - -Your server will start and listen for connections. With HTTP transport, you can access the API docs at http://127.0.0.1:8000/docs. - -### Configure MCP Clients - -Once your server is running, connect it to your favorite AI assistant: - -```bash -# Configure Claude Desktop (configures for stdio) -arcade configure claude --from-local - -# Configure Cursor (configures for http streamable) -arcade configure cursor --from-local - -# Configure VS Code (configures for http streamable) -arcade configure vscode --from-local -``` - - -## Client Integration - -Connect your MCP server with AI assistants and development tools: - -- **[Claude Desktop](clients/claude.md)** - Native MCP support in Claude -- **[Cursor IDE](clients/cursor.md)** - Enhanced AI coding with MCP tools -- **[VS Code](clients/vscode.md)** - Integrate with Visual Studio Code -- **[MCP Inspector](clients/inspector.md)** - Debug and test your tools - - -## Learn More - -- **[Walkthrough](examples/README.md)** - Comprehensive examples and tutorials -- **[API Reference](api/mcp_app.md)** - Detailed API documentation -- **[Transport Modes](advanced/transports.md)** - stdio and HTTP transport details - -## Community - -- [GitHub Repository](https://github.com/ArcadeAI/arcade-mcp) -- [Discord Community](https://discord.com/invite/GUZEMpEZ9p) -- [Documentation](https://docs.arcade.dev) - -## License - -Arcade MCP server is open source software licensed under the MIT license. diff --git a/libs/arcade-mcp-server/mkdocs.yml b/libs/arcade-mcp-server/mkdocs.yml deleted file mode 100644 index 4fa38607..00000000 --- a/libs/arcade-mcp-server/mkdocs.yml +++ /dev/null @@ -1,103 +0,0 @@ -site_name: Arcade MCP -site_description: MCP (Model Context Protocol) server framework from Arcade. -site_url: https://python.mcp.arcade.dev/ -repo_url: https://github.com/ArcadeAI/arcade-mcp -repo_name: ArcadeAI/arcade-mcp - -theme: - palette: - - media: "(prefers-color-scheme)" - toggle: - icon: material/brightness-auto - name: Switch to light mode - - media: "(prefers-color-scheme: light)" - scheme: default - toggle: - icon: material/brightness-7 - name: Switch to dark mode - - media: "(prefers-color-scheme: dark)" - scheme: slate - toggle: - icon: material/brightness-4 - name: Switch to system preference - name: material - logo: https://docs.arcade.dev/images/logo/arcade-logo.png - favicon: https://docs.arcade.dev/apple-touch-icon.png - - features: - - navigation.instant - - navigation.tracking - - navigation.expand - - navigation.indexes - - content.code.copy - - content.code.annotate - -markdown_extensions: - - pymdownx.highlight: - anchor_linenums: true - - pymdownx.inlinehilite - - pymdownx.snippets - - pymdownx.superfences - - admonition - - pymdownx.details - - pymdownx.tabbed: - alternate_style: true - - tables - - footnotes - - pymdownx.emoji: - emoji_index: !!python/name:material.extensions.emoji.twemoji - emoji_generator: !!python/name:material.extensions.emoji.to_svg - -plugins: - - search - - mkdocstrings: - handlers: - python: - paths: [../arcade_mcp_server] - options: - show_source: false - show_root_heading: true - heading_level: 3 - -exclude_docs: | - /README.md -nav: - - Home: index.md - - Getting Started: - - getting-started/quickstart.md - - Walkthrough: - - examples/README.md - - examples/00_hello_world.md - - examples/01_tools.md - - examples/02_building_apps.md - - examples/03_context.md - - examples/04_secrets.md - - examples/05_logging.md - - examples/06_tool_organization.md - - examples/07_auth.md - - Clients: - - clients/claude.md - - clients/cursor.md - - clients/vscode.md - - clients/inspector.md - - API Reference: - - api/mcp_app.md - - Server: - - api/server/server.md - - api/server/middleware.md - - api/server/types.md - - api/server/errors.md - - api/server/settings.md - - Advanced: - - advanced/sharing-servers.md - - advanced/transports.md - -extra: - social: - - icon: fontawesome/brands/github - link: https://github.com/ArcadeAI/arcade-mcp - - icon: fontawesome/brands/python - link: https://pypi.org/project/arcade-mcp/ - analytics: - provider: google - property: G-MG2E60KKVX diff --git a/libs/arcade-mcp-server/pyproject.toml b/libs/arcade-mcp-server/pyproject.toml index 0551f712..8e7edf12 100644 --- a/libs/arcade-mcp-server/pyproject.toml +++ b/libs/arcade-mcp-server/pyproject.toml @@ -41,9 +41,6 @@ dev = [ "pytest-asyncio>=0.23.0", "mypy>=1.0.0", "ruff>=0.1.0", - "mkdocs>=1.6.0", - "mkdocs-material>=9.6.0", - "mkdocstrings[python]>=0.28.0", ] [tool.hatch.build.targets.wheel]