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:
parent
7dd62fcc89
commit
a11f79b32d
30 changed files with 1095 additions and 522 deletions
|
|
@ -226,7 +226,6 @@ class MCPApp:
|
|||
asyncio.run(
|
||||
run_stdio_server(
|
||||
catalog=self._catalog,
|
||||
host=host,
|
||||
port=port,
|
||||
reload=reload,
|
||||
**self.server_kwargs,
|
||||
|
|
|
|||
180
libs/arcade-mcp-server/docs/advanced/sharing-servers.md
Normal file
180
libs/arcade-mcp-server/docs/advanced/sharing-servers.md
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
Binary file not shown.
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
191
libs/arcade-mcp-server/docs/examples/06_tool_organization.md
Normal file
191
libs/arcade-mcp-server/docs/examples/06_tool_organization.md
Normal 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.
|
||||
94
libs/arcade-mcp-server/docs/examples/06_tool_organization.py
Normal file
94
libs/arcade-mcp-server/docs/examples/06_tool_organization.py
Normal 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)
|
||||
123
libs/arcade-mcp-server/docs/examples/07_auth.md
Normal file
123
libs/arcade-mcp-server/docs/examples/07_auth.md
Normal 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
|
||||
73
libs/arcade-mcp-server/docs/examples/07_auth.py
Normal file
73
libs/arcade-mcp-server/docs/examples/07_auth.py
Normal 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)
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
31
libs/arcade-mcp-server/docs/examples/tools_math.py
Normal file
31
libs/arcade-mcp-server/docs/examples/tools_math.py
Normal 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
|
||||
29
libs/arcade-mcp-server/docs/examples/tools_text.py
Normal file
29
libs/arcade-mcp-server/docs/examples/tools_text.py
Normal 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]
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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" }]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue