Update arcade-mcp-server docs (#597)

1. Updates docs to prefer `uv run server.py` instead of `arcade mcp` or
`python -m arcade_mcp_server`
2. Found a bug with running stdio servers while updating the docs, so i
snuck that in this PR
This commit is contained in:
Eric Gustin 2025-10-02 17:16:38 -07:00 committed by GitHub
parent 7dd62fcc89
commit a11f79b32d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 1095 additions and 522 deletions

View file

@ -226,7 +226,6 @@ class MCPApp:
asyncio.run(
run_stdio_server(
catalog=self._catalog,
host=host,
port=port,
reload=reload,
**self.server_kwargs,

View file

@ -0,0 +1,180 @@
# 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

View file

@ -18,16 +18,16 @@ The stdio (standard input/output) transport is used for direct client connection
```bash
# Run with stdio transport
arcade mcp stdio
uv run server.py stdio
```
**Alternative: Direct Python**
```bash
# Using the module directly
python -m arcade_mcp_server stdio
# Run your server directly
uv run server.py stdio
# Or with MCPApp
# Or with python
app.run(transport="stdio")
```
@ -70,19 +70,17 @@ The HTTP transport provides REST/SSE endpoints for web-based clients.
```bash
# Run with HTTP transport (default)
arcade mcp
# With specific host and port
arcade mcp --host 0.0.0.0 --port 8080
uv run server.py
uv run server.py http
```
**Alternative: Direct Python**
```bash
# Using the module directly
python -m arcade_mcp_server
# Run your server directly
uv run server.py
# Or with MCPApp
# Or with python
app.run(transport="http", host="0.0.0.0", port=8080)
```
@ -99,9 +97,9 @@ When running in HTTP mode, the server provides:
**With Arcade CLI:**
```bash
```python
# Enable hot reload and debug mode
arcade mcp --reload --debug
app.run(host="127.0.0.1", port=8000, reload=True)
# This enables:
# - Automatic restart on code changes

View file

@ -1,137 +0,0 @@
# arcade mcp Command
The `arcade mcp` command is the recommended way to run MCP servers. It automatically discovers tools in your project, creates a server, and runs it with your chosen transport.
## Installation
```bash
uv pip install arcade-mcp
```
The `arcade-mcp` package includes the CLI and the `arcade-mcp-server` library.
## Command Line Options
```
usage: arcade mcp [-h] [--host HOST] [--port PORT]
[--tool-package PACKAGE] [--discover-installed]
[--show-packages] [--reload] [--debug]
[--env-file ENV_FILE] [--name NAME] [--version VERSION]
[--cwd CWD]
[transport]
Run Arcade MCP Server
positional arguments:
transport Transport type: stdio, http (default: http)
optional arguments:
-h, --help show this help message and exit
--host HOST Host to bind to (HTTP mode only, default: 127.0.0.1)
--port PORT Port to bind to (HTTP mode only, default: 8000)
--tool-package PACKAGE, --package PACKAGE, -p PACKAGE
Specific tool package to load (e.g., 'github' for arcade-github)
--discover-installed, --all
Discover all installed arcade tool packages
--show-packages Show loaded packages during discovery
--reload Enable auto-reload on code changes (HTTP mode only)
--debug Enable debug mode with verbose logging
--env-file ENV_FILE Path to environment file
--name NAME Server name
--version VERSION Server version
--cwd CWD Working directory to run from
```
## Basic Usage
```bash
# Run HTTP server (default)
arcade mcp
# Run stdio server (for Claude Desktop, Cursor, etc.)
arcade mcp stdio
# Run with debug logging
arcade mcp --debug
# Run with hot reload (development mode)
arcade mcp --reload --debug
```
## Tool Discovery
The CLI discovers tools in three ways:
### 1. Auto-Discovery (Default)
Automatically finds Python files with `@tool` decorated functions in:
- Current directory (`*.py`)
- `tools/` subdirectory
- `arcade_tools/` subdirectory
Example file structure:
```
my_project/
├── hello.py # Contains @tool functions
├── tools/
│ └── math.py # More @tool functions
└── arcade_tools/
└── utils.py # Even more @tool functions
```
### 2. Package Loading
Load specific arcade packages installed in your environment:
```bash
# Load arcade-github package
arcade mcp --tool-package github
# Load custom package (tries arcade_ prefix first)
arcade mcp -p mycompany_tools
```
### 3. Discover All Installed
Find and load all arcade packages in your Python environment:
```bash
# Load all arcade packages
arcade mcp --discover-installed
# Show what's being loaded
arcade mcp --discover-installed --show-packages
```
### Example Tool File
Create any Python file with `@tool` decorated functions:
```python
from arcade_mcp_server import tool
@tool
def hello(name: str) -> str:
"""Say hello to someone."""
return f"Hello, {name}!"
@tool
def add(a: int, b: int) -> int:
"""Add two numbers."""
return a + b
```
Then run:
```bash
arcade mcp # Auto-discovers and loads these tools
```
## Alternative: Direct Python Usage
While we recommend using `arcade mcp`, you can also run the server module directly:
```bash
python -m arcade_mcp_server [options]
```
This provides the same functionality but without the benefits of the Arcade CLI ecosystem (like `arcade configure` for client setup).

View file

@ -24,7 +24,7 @@ For MCP servers running over HTTP:
```bash
# Start your MCP server
python -m arcade_mcp_server --host 0.0.0.0 --port 8000
uv run server.py
# In another terminal, start the inspector
mcp-inspector http://localhost:8000/mcp
@ -36,10 +36,10 @@ For stdio-based servers:
```bash
# Start the inspector with your server command
mcp-inspector "python -m arcade_mcp_server stdio"
mcp-inspector "uv run server.py stdio"
# With additional arguments
mcp-inspector "python -m arcade_mcp_server stdio --tool-package github"
# With additional project directory
mcp-inspector --cwd /path/to/project "uv run server.py stdio"
```
## Inspector Features
@ -95,10 +95,10 @@ Pass environment variables to your server:
```bash
# Using env command
env ARCADE_API_KEY=your-key mcp-inspector "python -m arcade_mcp_server stdio"
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 "python -m arcade_mcp_server stdio"
mcp-inspector --env ARCADE_API_KEY=your-key "uv run server.py stdio"
```
### Working Directory
@ -106,7 +106,7 @@ mcp-inspector --env ARCADE_API_KEY=your-key "python -m arcade_mcp_server stdio"
Set the working directory for your server:
```bash
mcp-inspector --cwd /path/to/project "python -m arcade_mcp_server stdio"
mcp-inspector --cwd /path/to/project "uv run server.py stdio"
```
### Debug Mode
@ -114,20 +114,28 @@ mcp-inspector --cwd /path/to/project "python -m arcade_mcp_server stdio"
Enable verbose logging:
```bash
# Debug the MCP server
mcp-inspector "python -m arcade_mcp_server stdio --debug"
# Debug the inspector
mcp-inspector --debug "uv run server.py stdio"
# Debug the inspector itself
mcp-inspector --debug "python -m arcade_mcp_server 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. **Start your server with hot reload**:
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
python -m arcade_mcp_server --reload --debug
uv run server.py
```
2. **Connect the inspector**:
@ -213,8 +221,17 @@ def test_tool_via_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
python -m arcade_mcp_server --reload --debug --env-file .env.dev
uv run server.py
```
3. **Save Test Cases**:
@ -226,7 +243,7 @@ def test_tool_via_inspector():
1. **Test Against Production Config**:
```bash
mcp-inspector "python -m arcade_mcp_server stdio --env-file .env.prod"
mcp-inspector "uv run server.py stdio"
```
2. **Verify Security**:
@ -298,7 +315,7 @@ def add(
EOF
# 2. Start inspector
mcp-inspector "python -m arcade_mcp_server stdio"
mcp-inspector "uv run server.py stdio"
# 3. Test tools in the web interface
```
@ -338,17 +355,9 @@ export DEBUG=*
export MCP_DEBUG=true
# 2. Start server with verbose logging
python -m arcade_mcp_server stdio --debug 2>server.log
# (configure log_level="DEBUG" in your server.py)
uv run server.py stdio 2>server.log
# 3. Start inspector with debugging
mcp-inspector --debug "tail -f server.log" &
mcp-inspector --debug "python -m arcade_mcp_server stdio --debug"
mcp-inspector --debug "uv run server.py stdio"
```
## Tips and Tricks
1. **Bookmark Tool URLs**: Save frequently tested tools
2. **Export Test Data**: Save successful requests for documentation
3. **Use Browser DevTools**: Inspect network requests
4. **Create Tool Shortcuts**: Bookmark specific tool tests
5. **Monitor Resources**: Keep an eye on server resources during testing

View file

@ -18,7 +18,7 @@ Use VSCode's integrated terminal to run MCP servers:
1. Open integrated terminal (`Ctrl/Cmd + ` `)
2. Start your MCP server:
```bash
python -m arcade_mcp_server --reload --debug
uv run server.py
```
3. Use split terminals for multiple servers
@ -387,7 +387,7 @@ Run multiple MCP servers for different purposes:
{
"label": "Start API Tools",
"type": "shell",
"command": "python -m arcade_mcp_server --port 8001",
"command": "uv run server.py",
"options": {
"cwd": "${workspaceFolder}/api_tools"
},
@ -396,7 +396,7 @@ Run multiple MCP servers for different purposes:
{
"label": "Start Data Tools",
"type": "shell",
"command": "python -m arcade_mcp_server --port 8002",
"command": "uv run server.py",
"options": {
"cwd": "${workspaceFolder}/data_tools"
},
@ -405,7 +405,7 @@ Run multiple MCP servers for different purposes:
{
"label": "Start Utility Tools",
"type": "shell",
"command": "python -m arcade_mcp_server --port 8003",
"command": "uv run server.py",
"options": {
"cwd": "${workspaceFolder}/util_tools"
},
@ -426,19 +426,19 @@ Handle multiple environments:
{
"label": "MCP Server (Dev)",
"type": "shell",
"command": "python -m arcade_mcp_server --env-file .env.dev",
"command": "uv run --env-file .env.dev server.py",
"problemMatcher": []
},
{
"label": "MCP Server (Staging)",
"type": "shell",
"command": "python -m arcade_mcp_server --env-file .env.staging",
"command": "uv run --env-file .env.staging server.py",
"problemMatcher": []
},
{
"label": "MCP Server (Prod)",
"type": "shell",
"command": "python -m arcade_mcp_server --env-file .env.prod",
"command": "uv run --env-file .env.prod server.py",
"problemMatcher": [],
"presentation": {
"reveal": "always",

View file

@ -4,8 +4,8 @@ The simplest possible MCP server with a single tool using arcade-mcp-server.
## Running the Example
- **Run (HTTP default)**: `python -m arcade_mcp_server`
- **Run (stdio for Claude Desktop)**: `python -m arcade_mcp_server stdio`
- **Run (HTTP default)**: `uv run 00_hello_world.py`
- **Run (stdio for Claude Desktop)**: `uv run 00_hello_world.py stdio`
## Source Code
@ -15,7 +15,8 @@ The simplest possible MCP server with a single tool using arcade-mcp-server.
## Key Concepts
- **Minimal Setup**: Just import `@tool` decorator and annotate your function
- **Auto-Discovery**: The CLI automatically finds tools in your current directory
- **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

View file

@ -1,37 +1,38 @@
#!/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 a single tool using arcade-mcp-server with direct Python execution.
To run (auto-discovery):
1. Keep this file in the current directory
2. Run: python -m arcade_mcp_server
For Claude Desktop (stdio transport):
python -m arcade_mcp_server stdio
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 tool
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"
)
@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."
# That's it! The arcade_mcp_server CLI will handle everything else:
# - Creating the MCP server
# - Setting up the transport (stdio or HTTP)
# - Registering your tool
# - Handling all the protocol communication
if __name__ == "__main__":
# Check if stdio transport was requested
transport = "stdio" if len(sys.argv) > 1 and sys.argv[1] == "stdio" else "http"
# When you run `python -m arcade_mcp_server`, it will:
# 1. Discover this file (if in current directory)
# 2. Find the @tool decorated function
# 3. Create an MCP server with this tool
# 4. Start listening for requests
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)

View file

@ -4,11 +4,8 @@ Learn how to create tools with different parameter types and how arcade_mcp_serv
## Running the Example
- **Run**: `python -m arcade_mcp_server`
- **Run (stdio)**: `python -m arcade_mcp_server stdio`
- **Show loaded packages**: `python -m arcade_mcp_server --show-packages`
- **Load specific package**: `python -m arcade_mcp_server --tool-package github`
- **Discover all installed**: `python -m arcade_mcp_server --discover-installed`
- **Run (HTTP default)**: `uv run 01_tools.py`
- **Run (stdio for Claude Desktop)**: `uv run 01_tools.py stdio`
## Source Code
@ -23,12 +20,12 @@ Learn how to create tools with different parameter types and how arcade_mcp_serv
Basic tools with simple parameter types:
```python
@tool
@app.tool
def hello(name: Annotated[str, "Name to greet"]) -> str:
"""Say hello to someone."""
return f"Hello, {name}!"
@tool
@app.tool
def add(
a: Annotated[float, "First number"],
b: Annotated[float, "Second number"]
@ -42,7 +39,7 @@ def add(
Working with lists of values:
```python
@tool
@app.tool
def calculate_average(
numbers: Annotated[list[float], "List of numbers to average"]
) -> Annotated[float, "Average of all numbers"]:
@ -71,40 +68,43 @@ def create_user_profile(
# Implementation here
```
## Tool Discovery
## Managing Tools in MCPApp
The arcade_mcp_server CLI discovers tools in multiple ways:
With the direct Python approach, you have full control over your tools:
### 1. Current Directory
- Scans all `*.py` files in the current directory
- Imports and checks for `@tool` decorated functions
### 2. Standard Directories
- `tools/` directory - Common convention for organizing tools
- `arcade_tools/` directory - Alternative naming convention
- Both are recursively scanned for Python files
### 3. Package Loading
```bash
# Load a specific package
python -m arcade_mcp_server --tool-package github
# Discover all installed arcade packages
python -m arcade_mcp_server --discover-installed
### 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}"
```
### 4. File Organization
### 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/
├── hello.py # Contains @tool functions
├── server.py # Main MCPApp
├── tools/
│ └── math.py # More @tool functions
└── arcade_tools/
└── utils.py # Even more @tool functions
├── 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
@ -124,8 +124,8 @@ my_project/
## Key Concepts
- **Auto-Discovery**: Automatically finds tools without explicit registration
- **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
- **Flexible Organization**: Structure your tools however makes sense for your project
- **Multiple Sources**: Discover from files, directories, and packages
- **Import Flexibility**: Import tools from your own files and external packages
- **Direct Execution**: Run servers directly with `uv run` for better development experience

View file

@ -1,67 +1,40 @@
#!/usr/bin/env python
from typing import Annotated
from arcade_mcp_server import tool
from typing_extensions import TypedDict
#!/usr/bin/env python3
"""
01_tools.py - Tool creation, discovery, and parameter types
01_tools.py - Tool creation and parameter types
This example demonstrates:
1. How to create tools with the @tool decorator
1. How to create tools with @app.tool decorator in MCPApp
2. Different parameter types (simple, lists, TypedDict)
3. How arcade_mcp_server discovers tools automatically
3. Direct Python execution for better control
To run:
python -m arcade_mcp_server # Auto-discover all tools
python -m arcade_mcp_server --show-packages # Show what's being loaded
python -m arcade_mcp_server stdio # For Claude Desktop
uv run 01_tools.py # HTTP transport (default)
uv run 01_tools.py stdio # stdio transport for Claude Desktop
"""
# === DISCOVERY PATTERNS ===
import sys
from typing import Annotated
"""
The arcade_mcp_server CLI discovers tools using these patterns:
from arcade_mcp_server import MCPApp
from typing_extensions import TypedDict
1. Current directory: *.py files
- Scans all Python files in the current directory
- Imports and checks for @tool decorated functions
2. tools/ directory:
- If exists, recursively scans for Python files
- Common convention for organizing tools
3. arcade_tools/ directory:
- Alternative directory name
- Also recursively scanned
4. Package loading with --tool-package:
python -m arcade_mcp_server --tool-package github
- Loads arcade-github package
- Can load any installed package in the current python environment
5. Discover all installed with --discover-installed:
python -m arcade_mcp_server --discover-installed
- Finds all arcade-* packages in the current python environment
- Loads all their tools
Discovery tips:
- Use __init__.py in directories for proper imports
- Organize related tools in subdirectories
- Use clear, descriptive tool names
- Tools are namespaced by their toolkit name
"""
# Create the MCP application
app = MCPApp(
name="tools_example",
version="1.0.0",
instructions="Example server demonstrating various tool parameter types",
)
# === SIMPLE TOOLS ===
@tool
@app.tool
def hello(name: Annotated[str, "Name to greet"]) -> Annotated[str, "Greeting message"]:
"""Say hello to someone."""
return f"Hello, {name}!"
@tool
@app.tool
def add(
a: Annotated[float, "First number"], b: Annotated[float, "Second number"]
) -> Annotated[float, "Sum of the numbers"]:
@ -72,7 +45,7 @@ def add(
# === TOOLS WITH LIST PARAMETERS ===
@tool
@app.tool
def calculate_average(
numbers: Annotated[list[float], "List of numbers to average"],
) -> Annotated[float, "Average of all numbers"]:
@ -82,7 +55,7 @@ def calculate_average(
return sum(numbers) / len(numbers)
@tool
@app.tool
def factorial(n: Annotated[int, "Non-negative integer"]) -> Annotated[int, "Factorial of n"]:
"""Calculate the factorial of a number."""
if n < 0:
@ -106,7 +79,7 @@ class PersonInfo(TypedDict):
is_active: bool
@tool
@app.tool
def create_user_profile(
person: Annotated[PersonInfo, "Person's information"],
) -> Annotated[str, "Formatted user profile"]:
@ -129,7 +102,7 @@ class CalculationResult(TypedDict):
count: int
@tool
@app.tool
def analyze_numbers(
values: Annotated[list[float], "List of numbers to analyze"],
) -> Annotated[CalculationResult, "Statistical analysis of the numbers"]:
@ -144,3 +117,14 @@ def analyze_numbers(
"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)

View file

@ -31,7 +31,8 @@ app = MCPApp(
### 2. Adding Tools
Use the `@app.tool` decorator to add 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:
@ -39,6 +40,29 @@ def my_tool(param: Annotated[str, "Description"]) -> str:
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

View file

@ -63,4 +63,4 @@ if __name__ == "__main__":
app.run(transport="stdio")
else:
# Default to HTTP transport
app.run(host="127.0.0.1", port=8001)
app.run(host="127.0.0.1", port=8000)

View file

@ -4,8 +4,8 @@ Access runtime features through Context including logging, secrets, and progress
## Running the Example
- **Run**: `python -m arcade_mcp_server`
- **Run (stdio)**: `python -m arcade_mcp_server stdio`
- **Run**: `uv run 03_context.py`
- **Run (stdio)**: `uv run 03_context.py stdio`
- **Env**: set `API_KEY`, `DATABASE_URL`
## Source Code

View file

@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
"""
03_context.py - Using Context with namespaced runtime APIs
@ -6,23 +6,29 @@ 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 (auto-discovery):
python -m arcade_mcp_server
For Claude Desktop (stdio transport):
python -m arcade_mcp_server stdio
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, tool
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",
)
@tool
@app.tool
async def secure_api_call(
context: Context,
endpoint: Annotated[str, "API endpoint to call"],
@ -44,7 +50,8 @@ async def secure_api_call(
return f"Successfully called {endpoint} with API key: {api_key[:4]}..."
@tool(requires_secrets=["DATABASE_URL"])
# 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"]:
@ -71,7 +78,7 @@ async def database_info(
return f"{user_info}\nDatabase: {db_url}"
@tool
@app.tool
async def debug_context(
context: Context,
show_secrets: Annotated[bool, "Whether to show secret keys (not values)"] = False,
@ -92,7 +99,7 @@ async def debug_context(
return info
@tool
@app.tool
async def process_with_progress(
context: Context,
items: Annotated[list[str], "Items to process"],
@ -136,3 +143,13 @@ async def process_with_progress(
# - context.get_secret(key): Retrieve a secret value (raises if missing)
# - context.log.<level>(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)

View file

@ -4,14 +4,14 @@ Read secrets from environment and `.env` files securely via Context.
## Running the Example
- **Run**: `python -m arcade_mcp_server`
- **Run (stdio)**: `python -m arcade_mcp_server stdio`
- **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_tool_secrets.py"
--8<-- "docs/examples/04_secrets.py"
```
## Working with Secrets
@ -22,12 +22,11 @@ Secrets can be provided via environment variables:
```bash
export API_KEY="your-secret-key"
export DATABASE_URL="postgresql://localhost/mydb"
python -m arcade_mcp_server
```
### 2. Using .env Files
Create a `.env` file in your working directory:
Create a `.env` file in the directoryof your server:
```
API_KEY=supersecret
DATABASE_URL=postgresql://user:pass@localhost/db

View file

@ -1,23 +1,28 @@
#!/usr/bin/env python3
"""04: Read secrets from .env via Context
Run (auto-discovery):
python -m arcade_mcp_server
For Claude Desktop (stdio transport):
python -m arcade_mcp_server stdio
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
"""
from arcade_mcp_server import Context, tool
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",
)
@tool(
name="UseSecret",
desc="Echo a masked secret read from the context",
@app.tool(
requires_secrets=["API_KEY"], # declare we need API_KEY
)
def use_secret(context: Context) -> str:
@ -28,3 +33,14 @@ def use_secret(context: Context) -> str:
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)

View file

@ -187,4 +187,4 @@ async def batch_processing_logs(
if __name__ == "__main__":
# Run the server
app.run(host="127.0.0.1", port=8001)
app.run(host="127.0.0.1", port=8000)

View file

@ -0,0 +1,191 @@
# 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.

View file

@ -0,0 +1,94 @@
#!/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)

View file

@ -0,0 +1,123 @@
# 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

View file

@ -0,0 +1,73 @@
#!/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)

View file

@ -4,83 +4,81 @@ This directory contains examples demonstrating how to build MCP servers with you
## Getting Started
The easiest way to get started is with the `arcade new` command:
The easiest way to get started is with `arcade new`:
```bash
# Install the Arcade CLI
# Install the CLI
uv pip install arcade-mcp
# Create a new server with example tools
# Create a new server project with example tools
arcade new my_server
cd my_server
# Run the server
arcade mcp
# 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: `arcade mcp` (or `arcade mcp stdio`)
- 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: `arcade mcp`
- 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: `python 02_building_apps.py`
- Run stdio: `python 02_building_apps.py stdio`
- 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: `arcade mcp`
- Run: `uv run 03_context.py`
5. **[04_tool_secrets.py](04_tool_secrets.py)** Working with secrets
5. **[04_tool_secrets.py](04_secrets.py)** Working with secrets
- Use `requires_secrets` and access masked values
- Run: `arcade mcp`
- 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: `python 05_logging.py`
- 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: Using the Arcade CLI
### Recommended: Direct Python Execution
Most examples can be run with the `arcade mcp` command:
Most examples can be run directly with Python using `uv`:
```bash
# Auto-discover tools in current directory
arcade mcp
# 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
arcade mcp stdio # For Claude Desktop
arcade mcp # HTTP by default
uv run server.py stdio # For Claude Desktop
uv run server.py http # HTTP by default
# With debugging
arcade mcp --debug
# With hot reload (HTTP only)
arcade mcp --reload
# You can also run with python directly
python 00_hello_world.py
python 02_building_apps.py stdio
```
### Alternative: Direct Python Execution
For MCPApp examples, you can run the script directly:
```bash
python 02_building_apps.py
```
Or use the server module directly:
```bash
python -m arcade_mcp_server
```
**Note:** We recommend using `arcade mcp` for a better development experience.
All example files include proper command-line argument handling with `if __name__ == "__main__":` blocks.

View file

@ -0,0 +1,31 @@
#!/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

View file

@ -0,0 +1,29 @@
#!/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]

View file

@ -1,8 +1,8 @@
# Quick Start
The `arcade_mcp_server` package provides powerful ways to run MCP servers with your Arcade tools. While you can use the server library directly, **we recommend using the Arcade CLI** for a streamlined development experience.
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: Quick Start with Arcade CLI
## Recommended: Create with arcade new
### 1. Install the CLI
@ -10,44 +10,66 @@ The `arcade_mcp_server` package provides powerful ways to run MCP servers with y
uv pip install arcade-mcp
```
The `arcade-mcp` package includes both the CLI tools and the `arcade-mcp-server` library.
The `arcade-mcp` package includes the CLI tools and the `arcade-mcp-server` library.
### 2. Create a New Server
Start with a pre-configured server that includes example tools:
### 2. Create Your Server
```bash
arcade new my_server
cd my_server
```
This creates a starter MCP server with three example tools:
- **Simple tool** - A basic greeting function
- **Secret-based tool** - Demonstrates using environment secrets
- **OAuth tool** - Shows user authentication flow (requires `arcade login`)
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 HTTP server (default, great for development)
arcade mcp
# Run with uv (recommended)
uv run server.py
# Or run stdio server (for Claude Desktop, Cursor, etc.)
arcade mcp stdio
# 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
DEBUG | 11:43:11 | arcade_mcp_server.mcp_app:169 | Added tool: greet
INFO | 11:43:11 | arcade_mcp_server.mcp_app:211 | Starting server v1.0.0 with 3 tools
INFO: Started server process [89481]
INFO: Waiting for application startup.
INFO | 11:43:12 | arcade_mcp_server.worker:69 | MCP server started and ready for connections
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
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
```
View your server's API docs at http://127.0.0.1:8000/docs.
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
@ -66,39 +88,6 @@ arcade configure vscode --from-local
That's it! Your MCP server is running and connected to your AI assistant.
## Alternative: Direct Python Approach
If you prefer to use the library directly without the CLI, you can install just the server package:
```bash
uv pip install arcade-mcp-server
```
### Write a Tool
```python
from arcade_mcp_server import tool
from typing import Annotated
@tool
def greet(name: Annotated[str, "The name to greet"]) -> Annotated[str, "The greeting"]:
return f"Hello, {name}!"
```
### Run the Server
You can run the server directly with Python:
```bash
# Using the module directly
python -m arcade_mcp_server
# Or if you have a server.py file with MCPApp
python server.py
```
**Note:** While this approach works, we recommend using `arcade mcp` for a better development experience with features like easy client configuration and starter templates.
## Building MCP Servers
@ -109,7 +98,7 @@ from arcade_mcp_server import MCPApp
from typing import Annotated
app = MCPApp(
name="my-tools",
name="my_serve_",
version="1.0.0",
instructions="Custom MCP server with specialized tools"
)
@ -135,72 +124,13 @@ if __name__ == "__main__":
app.run(host="0.0.0.0", port=8080, reload=True)
```
## Using the `arcade mcp` Command
The `arcade mcp` command provides a simple interface for running MCP servers. It automatically discovers tools, creates a server, and runs it with your chosen transport.
### Auto-Discovery Mode
## Secrets
The simplest way to run is to let the server discover tools in your current directory:
Define your tool secrets in an environment file `.env` in the same directory as your `MCPApp`, or export as environment variables
```bash
# Auto-discover @tool decorated functions
arcade mcp
# With stdio transport for Claude Desktop
arcade mcp stdio
```
### Loading Installed Packages
Load specific arcade packages or discover all installed ones:
```bash
# Load a specific arcade package
arcade mcp --tool-package github
arcade mcp -p slack
# Discover all installed arcade packages
arcade mcp --discover-installed
# Show which packages are being loaded
arcade mcp --discover-installed --show-packages
```
### Development Mode
For active development with hot reload:
```bash
# Run with hot reload and debug logging
arcade mcp --reload --debug
# Specify host and port
arcade mcp --host 0.0.0.0 --port 8000
# Load environment variables
arcade mcp --env-file .env
```
## Environment Variables
Configure the server using environment variables:
```bash
# Server settings
MCP_SERVER_NAME="My MCP Server"
MCP_SERVER_VERSION="1.0.0"
# Arcade integration
ARCADE_API_KEY="your-api-key"
ARCADE_API_URL="https://api.arcade.dev"
ARCADE_USER_ID="user@example.com"
# Development settings
ARCADE_AUTH_DISABLED=true
MCP_DEBUG=true
# Tool secrets (available to tools via context)
MY_API_KEY="secret-value"
DATABASE_URL="postgresql://..."
@ -209,20 +139,22 @@ DATABASE_URL="postgresql://..."
## Development Tips
### Hot Reload
Use `--reload --debug` for development to automatically restart on code changes:
Use the `reload=True` parameter for development to automatically restart on code changes:
```bash
arcade mcp --reload --debug
```python
app.run(host="127.0.0.1", port=8000, reload=True)
```
### Logging
- Use `--debug` for verbose logging
- Set `log_level="DEBUG"` in MCPApp for verbose logging
- In stdio mode, logs go to stderr
- In HTTP mode, logs go to stdout
### Testing Tools
With HTTP transport and debug mode, access API documentation at:
### 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

View file

@ -27,47 +27,50 @@ Arcade MCP (Model Context Protocol) enables AI assistants and development tools
### Installation
We recommend installing the `arcade-mcp` CLI package, which includes `arcade-mcp-server` and provides a streamlined development workflow:
```bash
uv pip install arcade-mcp
```
Or install just the server library if you prefer a direct Python approach:
We recommend installing the `arcade-mcp-server` library for direct Python development:
```bash
uv pip install arcade-mcp-server
```
### Quick Start: Create a New Server (Recommended)
The fastest way to get started is with the `arcade new` command, which creates a starter MCP server with example tools:
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
# Run the server
arcade mcp
```
The generated server includes three example tools:
- **Simple tool** - A basic function to get you started
- **Secret-based tool** - Shows how to use environment secrets
- **OAuth tool** - Demonstrates how to use a OAuth tool (requires `arcade login`)
This generates a complete project with:
### Manual Setup: Create Your First Tool
- **server.py** - Main server file with MCPApp and example tools
If you prefer to create tools manually, you can use the `MCPApp` interface:
- **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
from arcade_mcp_server import MCPApp
#!/usr/bin/env python3
import sys
from typing import Annotated
from arcade_mcp_server import MCPApp
app = MCPApp(name="my-tools", version="1.0.0")
app = MCPApp(name="my_server", version="1.0.0")
@app.tool
def greet(name: Annotated[str, "Name to greet"]) -> str:
@ -75,30 +78,36 @@ def greet(name: Annotated[str, "Name to greet"]) -> str:
return f"Hello, {name}!"
if __name__ == "__main__":
app.run()
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
**Recommended: Use the Arcade CLI**
Run your server directly with Python:
```bash
# Run HTTP server (default)
arcade mcp
# Run with HTTP transport (default)
uv run server.py
# Run stdio server (for Claude Desktop, Cursor, etc.)
arcade mcp stdio
# Run with stdio transport (for Claude Desktop)
uv run server.py stdio
# Run with debug logging and hot reload
arcade mcp --debug --reload
# Or use python directly
python server.py http
python server.py stdio
```
**Alternative: Direct Python execution**
```bash
# Run your server.py file directly
python server.py
```
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

View file

@ -73,6 +73,8 @@ nav:
- 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
@ -80,7 +82,6 @@ nav:
- clients/inspector.md
- API Reference:
- api/mcp_app.md
- api/cli.md
- Server:
- api/server/server.md
- api/server/middleware.md
@ -88,6 +89,7 @@ nav:
- api/server/errors.md
- api/server/settings.md
- Advanced:
- advanced/sharing-servers.md
- advanced/transports.md
extra:

View file

@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "arcade-mcp-server"
version = "1.0.0rc2"
version = "1.0.0rc3"
description = "Model Context Protocol (MCP) server framework for Arcade.dev"
readme = "README.md"
authors = [{ name = "Arcade.dev" }]

View file

@ -21,7 +21,7 @@ requires-python = ">=3.10"
dependencies = [
# CLI dependencies
"arcade-mcp-server>=1.0.0rc2,<3.0.0",
"arcade-mcp-server>=1.0.0rc3,<3.0.0",
"arcade-core>=2.5.0rc2,<3.0.0",
"typer==0.10.0",
"rich==13.9.4",
@ -41,7 +41,7 @@ all = [
"pytz>=2024.1",
"python-dateutil>=2.8.2",
# mcp
"arcade-mcp-server>=1.0.0rc2,<3.0.0",
"arcade-mcp-server>=1.0.0rc3,<3.0.0",
# serve
"arcade-serve>=2.2.0rc2,<3.0.0",
# tdk