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(
|
asyncio.run(
|
||||||
run_stdio_server(
|
run_stdio_server(
|
||||||
catalog=self._catalog,
|
catalog=self._catalog,
|
||||||
host=host,
|
|
||||||
port=port,
|
port=port,
|
||||||
reload=reload,
|
reload=reload,
|
||||||
**self.server_kwargs,
|
**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
|
```bash
|
||||||
# Run with stdio transport
|
# Run with stdio transport
|
||||||
arcade mcp stdio
|
uv run server.py stdio
|
||||||
```
|
```
|
||||||
|
|
||||||
**Alternative: Direct Python**
|
**Alternative: Direct Python**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Using the module directly
|
# Run your server directly
|
||||||
python -m arcade_mcp_server stdio
|
uv run server.py stdio
|
||||||
|
|
||||||
# Or with MCPApp
|
# Or with python
|
||||||
app.run(transport="stdio")
|
app.run(transport="stdio")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -70,19 +70,17 @@ The HTTP transport provides REST/SSE endpoints for web-based clients.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Run with HTTP transport (default)
|
# Run with HTTP transport (default)
|
||||||
arcade mcp
|
uv run server.py
|
||||||
|
uv run server.py http
|
||||||
# With specific host and port
|
|
||||||
arcade mcp --host 0.0.0.0 --port 8080
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Alternative: Direct Python**
|
**Alternative: Direct Python**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Using the module directly
|
# Run your server directly
|
||||||
python -m arcade_mcp_server
|
uv run server.py
|
||||||
|
|
||||||
# Or with MCPApp
|
# Or with python
|
||||||
app.run(transport="http", host="0.0.0.0", port=8080)
|
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:**
|
**With Arcade CLI:**
|
||||||
|
|
||||||
```bash
|
```python
|
||||||
# Enable hot reload and debug mode
|
# Enable hot reload and debug mode
|
||||||
arcade mcp --reload --debug
|
app.run(host="127.0.0.1", port=8000, reload=True)
|
||||||
|
|
||||||
# This enables:
|
# This enables:
|
||||||
# - Automatic restart on code changes
|
# - 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
|
```bash
|
||||||
# Start your MCP server
|
# 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
|
# In another terminal, start the inspector
|
||||||
mcp-inspector http://localhost:8000/mcp
|
mcp-inspector http://localhost:8000/mcp
|
||||||
|
|
@ -36,10 +36,10 @@ For stdio-based servers:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Start the inspector with your server command
|
# 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
|
# With additional project directory
|
||||||
mcp-inspector "python -m arcade_mcp_server stdio --tool-package github"
|
mcp-inspector --cwd /path/to/project "uv run server.py stdio"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Inspector Features
|
## Inspector Features
|
||||||
|
|
@ -95,10 +95,10 @@ Pass environment variables to your server:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Using env command
|
# 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
|
# 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
|
### 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:
|
Set the working directory for your server:
|
||||||
|
|
||||||
```bash
|
```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
|
### Debug Mode
|
||||||
|
|
@ -114,20 +114,28 @@ mcp-inspector --cwd /path/to/project "python -m arcade_mcp_server stdio"
|
||||||
Enable verbose logging:
|
Enable verbose logging:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Debug the MCP server
|
# Debug the inspector
|
||||||
mcp-inspector "python -m arcade_mcp_server stdio --debug"
|
mcp-inspector --debug "uv run server.py stdio"
|
||||||
|
|
||||||
# Debug the inspector itself
|
# Server debug logging is configured in your server.py
|
||||||
mcp-inspector --debug "python -m arcade_mcp_server stdio"
|
# app = MCPApp(name="my_server", version="1.0.0", log_level="DEBUG")
|
||||||
```
|
```
|
||||||
|
|
||||||
## Testing Workflows
|
## Testing Workflows
|
||||||
|
|
||||||
### Tool Development
|
### 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
|
```bash
|
||||||
python -m arcade_mcp_server --reload --debug
|
uv run server.py
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **Connect the inspector**:
|
2. **Connect the inspector**:
|
||||||
|
|
@ -213,8 +221,17 @@ def test_tool_via_inspector():
|
||||||
- Terminal 3: Code editor
|
- Terminal 3: Code editor
|
||||||
|
|
||||||
2. **Enable All Debugging**:
|
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
|
```bash
|
||||||
python -m arcade_mcp_server --reload --debug --env-file .env.dev
|
uv run server.py
|
||||||
```
|
```
|
||||||
|
|
||||||
3. **Save Test Cases**:
|
3. **Save Test Cases**:
|
||||||
|
|
@ -226,7 +243,7 @@ def test_tool_via_inspector():
|
||||||
|
|
||||||
1. **Test Against Production Config**:
|
1. **Test Against Production Config**:
|
||||||
```bash
|
```bash
|
||||||
mcp-inspector "python -m arcade_mcp_server stdio --env-file .env.prod"
|
mcp-inspector "uv run server.py stdio"
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **Verify Security**:
|
2. **Verify Security**:
|
||||||
|
|
@ -298,7 +315,7 @@ def add(
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# 2. Start inspector
|
# 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
|
# 3. Test tools in the web interface
|
||||||
```
|
```
|
||||||
|
|
@ -338,17 +355,9 @@ export DEBUG=*
|
||||||
export MCP_DEBUG=true
|
export MCP_DEBUG=true
|
||||||
|
|
||||||
# 2. Start server with verbose logging
|
# 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
|
# 3. Start inspector with debugging
|
||||||
mcp-inspector --debug "tail -f server.log" &
|
mcp-inspector --debug "uv run server.py stdio"
|
||||||
mcp-inspector --debug "python -m arcade_mcp_server stdio --debug"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 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 + ` `)
|
1. Open integrated terminal (`Ctrl/Cmd + ` `)
|
||||||
2. Start your MCP server:
|
2. Start your MCP server:
|
||||||
```bash
|
```bash
|
||||||
python -m arcade_mcp_server --reload --debug
|
uv run server.py
|
||||||
```
|
```
|
||||||
3. Use split terminals for multiple servers
|
3. Use split terminals for multiple servers
|
||||||
|
|
||||||
|
|
@ -387,7 +387,7 @@ Run multiple MCP servers for different purposes:
|
||||||
{
|
{
|
||||||
"label": "Start API Tools",
|
"label": "Start API Tools",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "python -m arcade_mcp_server --port 8001",
|
"command": "uv run server.py",
|
||||||
"options": {
|
"options": {
|
||||||
"cwd": "${workspaceFolder}/api_tools"
|
"cwd": "${workspaceFolder}/api_tools"
|
||||||
},
|
},
|
||||||
|
|
@ -396,7 +396,7 @@ Run multiple MCP servers for different purposes:
|
||||||
{
|
{
|
||||||
"label": "Start Data Tools",
|
"label": "Start Data Tools",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "python -m arcade_mcp_server --port 8002",
|
"command": "uv run server.py",
|
||||||
"options": {
|
"options": {
|
||||||
"cwd": "${workspaceFolder}/data_tools"
|
"cwd": "${workspaceFolder}/data_tools"
|
||||||
},
|
},
|
||||||
|
|
@ -405,7 +405,7 @@ Run multiple MCP servers for different purposes:
|
||||||
{
|
{
|
||||||
"label": "Start Utility Tools",
|
"label": "Start Utility Tools",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "python -m arcade_mcp_server --port 8003",
|
"command": "uv run server.py",
|
||||||
"options": {
|
"options": {
|
||||||
"cwd": "${workspaceFolder}/util_tools"
|
"cwd": "${workspaceFolder}/util_tools"
|
||||||
},
|
},
|
||||||
|
|
@ -426,19 +426,19 @@ Handle multiple environments:
|
||||||
{
|
{
|
||||||
"label": "MCP Server (Dev)",
|
"label": "MCP Server (Dev)",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "python -m arcade_mcp_server --env-file .env.dev",
|
"command": "uv run --env-file .env.dev server.py",
|
||||||
"problemMatcher": []
|
"problemMatcher": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "MCP Server (Staging)",
|
"label": "MCP Server (Staging)",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "python -m arcade_mcp_server --env-file .env.staging",
|
"command": "uv run --env-file .env.staging server.py",
|
||||||
"problemMatcher": []
|
"problemMatcher": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "MCP Server (Prod)",
|
"label": "MCP Server (Prod)",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "python -m arcade_mcp_server --env-file .env.prod",
|
"command": "uv run --env-file .env.prod server.py",
|
||||||
"problemMatcher": [],
|
"problemMatcher": [],
|
||||||
"presentation": {
|
"presentation": {
|
||||||
"reveal": "always",
|
"reveal": "always",
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ The simplest possible MCP server with a single tool using arcade-mcp-server.
|
||||||
|
|
||||||
## Running the Example
|
## Running the Example
|
||||||
|
|
||||||
- **Run (HTTP default)**: `python -m arcade_mcp_server`
|
- **Run (HTTP default)**: `uv run 00_hello_world.py`
|
||||||
- **Run (stdio for Claude Desktop)**: `python -m arcade_mcp_server stdio`
|
- **Run (stdio for Claude Desktop)**: `uv run 00_hello_world.py stdio`
|
||||||
|
|
||||||
## Source Code
|
## Source Code
|
||||||
|
|
||||||
|
|
@ -15,7 +15,8 @@ The simplest possible MCP server with a single tool using arcade-mcp-server.
|
||||||
|
|
||||||
## Key Concepts
|
## Key Concepts
|
||||||
|
|
||||||
- **Minimal Setup**: Just import `@tool` decorator and annotate your function
|
- **Minimal Setup**: Create `MCPApp`, define tools with `@app.tool`, and run with `app.run()`
|
||||||
- **Auto-Discovery**: The CLI automatically finds tools in your current directory
|
- **Direct Execution**: Run your server file directly with `uv run` or `python`
|
||||||
- **Transport Flexibility**: Works with both stdio (for Claude Desktop) and HTTP
|
- **Transport Flexibility**: Works with both stdio (for Claude Desktop) and HTTP
|
||||||
- **Type Annotations**: Use `Annotated` to provide descriptions for parameters and return values
|
- **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
|
00_hello_world.py - The simplest possible MCP server
|
||||||
|
|
||||||
This example shows the absolute minimum code needed to create an 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):
|
To run:
|
||||||
1. Keep this file in the current directory
|
uv run 00_hello_world.py # HTTP transport (default)
|
||||||
2. Run: python -m arcade_mcp_server
|
uv run 00_hello_world.py stdio # stdio transport for Claude Desktop
|
||||||
|
|
||||||
For Claude Desktop (stdio transport):
|
|
||||||
python -m arcade_mcp_server stdio
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
from typing import Annotated
|
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"]:
|
def greet(name: Annotated[str, "Name of the person to greet"]) -> Annotated[str, "Welcome message"]:
|
||||||
"""Greet a person by name with a welcome message."""
|
"""Greet a person by name with a welcome message."""
|
||||||
|
|
||||||
return f"Hello, {name}! Welcome to Arcade MCP."
|
return f"Hello, {name}! Welcome to Arcade MCP."
|
||||||
|
|
||||||
|
|
||||||
# That's it! The arcade_mcp_server CLI will handle everything else:
|
if __name__ == "__main__":
|
||||||
# - Creating the MCP server
|
# Check if stdio transport was requested
|
||||||
# - Setting up the transport (stdio or HTTP)
|
transport = "stdio" if len(sys.argv) > 1 and sys.argv[1] == "stdio" else "http"
|
||||||
# - Registering your tool
|
|
||||||
# - Handling all the protocol communication
|
|
||||||
|
|
||||||
# When you run `python -m arcade_mcp_server`, it will:
|
print(f"Starting {app.name} v{app.version}")
|
||||||
# 1. Discover this file (if in current directory)
|
print(f"Transport: {transport}")
|
||||||
# 2. Find the @tool decorated function
|
|
||||||
# 3. Create an MCP server with this tool
|
# Run the server
|
||||||
# 4. Start listening for requests
|
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
|
## Running the Example
|
||||||
|
|
||||||
- **Run**: `python -m arcade_mcp_server`
|
- **Run (HTTP default)**: `uv run 01_tools.py`
|
||||||
- **Run (stdio)**: `python -m arcade_mcp_server stdio`
|
- **Run (stdio for Claude Desktop)**: `uv run 01_tools.py 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`
|
|
||||||
|
|
||||||
## Source Code
|
## 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:
|
Basic tools with simple parameter types:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@tool
|
@app.tool
|
||||||
def hello(name: Annotated[str, "Name to greet"]) -> str:
|
def hello(name: Annotated[str, "Name to greet"]) -> str:
|
||||||
"""Say hello to someone."""
|
"""Say hello to someone."""
|
||||||
return f"Hello, {name}!"
|
return f"Hello, {name}!"
|
||||||
|
|
||||||
@tool
|
@app.tool
|
||||||
def add(
|
def add(
|
||||||
a: Annotated[float, "First number"],
|
a: Annotated[float, "First number"],
|
||||||
b: Annotated[float, "Second number"]
|
b: Annotated[float, "Second number"]
|
||||||
|
|
@ -42,7 +39,7 @@ def add(
|
||||||
Working with lists of values:
|
Working with lists of values:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@tool
|
@app.tool
|
||||||
def calculate_average(
|
def calculate_average(
|
||||||
numbers: Annotated[list[float], "List of numbers to average"]
|
numbers: Annotated[list[float], "List of numbers to average"]
|
||||||
) -> Annotated[float, "Average of all numbers"]:
|
) -> Annotated[float, "Average of all numbers"]:
|
||||||
|
|
@ -71,40 +68,43 @@ def create_user_profile(
|
||||||
# Implementation here
|
# 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
|
### 1. Defining Tools Directily
|
||||||
- Scans all `*.py` files in the current directory
|
Use `@app.tool` to define tools directly on your MCPApp instance:
|
||||||
- Imports and checks for `@tool` decorated functions
|
```python
|
||||||
|
@app.tool
|
||||||
### 2. Standard Directories
|
def my_tool(param: str) -> str:
|
||||||
- `tools/` directory - Common convention for organizing tools
|
"""Tool description."""
|
||||||
- `arcade_tools/` directory - Alternative naming convention
|
return f"Processed: {param}"
|
||||||
- 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
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 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:
|
Example project structure:
|
||||||
```
|
```
|
||||||
my_project/
|
my_project/
|
||||||
├── hello.py # Contains @tool functions
|
├── server.py # Main MCPApp
|
||||||
├── tools/
|
├── tools/
|
||||||
│ └── math.py # More @tool functions
|
│ ├── math.py # Tools using @tool decorator
|
||||||
└── arcade_tools/
|
│ └── utils.py # More tools
|
||||||
└── utils.py # Even more @tool functions
|
└── pyproject.toml # Dependencies
|
||||||
```
|
```
|
||||||
|
|
||||||
|
This approach gives you explicit control over which tools are loaded and how they're organized.
|
||||||
|
|
||||||
## Best Practices
|
## Best Practices
|
||||||
|
|
||||||
### Parameter Annotations
|
### Parameter Annotations
|
||||||
|
|
@ -124,8 +124,8 @@ my_project/
|
||||||
|
|
||||||
## Key Concepts
|
## 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
|
- **Type Safety**: Full type annotation support with runtime validation
|
||||||
- **TypedDict Support**: Use TypedDict for complex structured data
|
- **TypedDict Support**: Use TypedDict for complex structured data
|
||||||
- **Flexible Organization**: Structure your tools however makes sense for your project
|
- **Import Flexibility**: Import tools from your own files and external packages
|
||||||
- **Multiple Sources**: Discover from files, directories, and packages
|
- **Direct Execution**: Run servers directly with `uv run` for better development experience
|
||||||
|
|
|
||||||
|
|
@ -1,67 +1,40 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
from typing import Annotated
|
|
||||||
|
|
||||||
from arcade_mcp_server import tool
|
|
||||||
from typing_extensions import TypedDict
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
01_tools.py - Tool creation, discovery, and parameter types
|
01_tools.py - Tool creation and parameter types
|
||||||
|
|
||||||
This example demonstrates:
|
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)
|
2. Different parameter types (simple, lists, TypedDict)
|
||||||
3. How arcade_mcp_server discovers tools automatically
|
3. Direct Python execution for better control
|
||||||
|
|
||||||
To run:
|
To run:
|
||||||
python -m arcade_mcp_server # Auto-discover all tools
|
uv run 01_tools.py # HTTP transport (default)
|
||||||
python -m arcade_mcp_server --show-packages # Show what's being loaded
|
uv run 01_tools.py stdio # stdio transport for Claude Desktop
|
||||||
python -m arcade_mcp_server stdio # For Claude Desktop
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# === DISCOVERY PATTERNS ===
|
import sys
|
||||||
|
from typing import Annotated
|
||||||
|
|
||||||
"""
|
from arcade_mcp_server import MCPApp
|
||||||
The arcade_mcp_server CLI discovers tools using these patterns:
|
from typing_extensions import TypedDict
|
||||||
|
|
||||||
1. Current directory: *.py files
|
# Create the MCP application
|
||||||
- Scans all Python files in the current directory
|
app = MCPApp(
|
||||||
- Imports and checks for @tool decorated functions
|
name="tools_example",
|
||||||
|
version="1.0.0",
|
||||||
2. tools/ directory:
|
instructions="Example server demonstrating various tool parameter types",
|
||||||
- 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
|
|
||||||
"""
|
|
||||||
|
|
||||||
# === SIMPLE TOOLS ===
|
# === SIMPLE TOOLS ===
|
||||||
|
|
||||||
|
|
||||||
@tool
|
@app.tool
|
||||||
def hello(name: Annotated[str, "Name to greet"]) -> Annotated[str, "Greeting message"]:
|
def hello(name: Annotated[str, "Name to greet"]) -> Annotated[str, "Greeting message"]:
|
||||||
"""Say hello to someone."""
|
"""Say hello to someone."""
|
||||||
return f"Hello, {name}!"
|
return f"Hello, {name}!"
|
||||||
|
|
||||||
|
|
||||||
@tool
|
@app.tool
|
||||||
def add(
|
def add(
|
||||||
a: Annotated[float, "First number"], b: Annotated[float, "Second number"]
|
a: Annotated[float, "First number"], b: Annotated[float, "Second number"]
|
||||||
) -> Annotated[float, "Sum of the numbers"]:
|
) -> Annotated[float, "Sum of the numbers"]:
|
||||||
|
|
@ -72,7 +45,7 @@ def add(
|
||||||
# === TOOLS WITH LIST PARAMETERS ===
|
# === TOOLS WITH LIST PARAMETERS ===
|
||||||
|
|
||||||
|
|
||||||
@tool
|
@app.tool
|
||||||
def calculate_average(
|
def calculate_average(
|
||||||
numbers: Annotated[list[float], "List of numbers to average"],
|
numbers: Annotated[list[float], "List of numbers to average"],
|
||||||
) -> Annotated[float, "Average of all numbers"]:
|
) -> Annotated[float, "Average of all numbers"]:
|
||||||
|
|
@ -82,7 +55,7 @@ def calculate_average(
|
||||||
return sum(numbers) / len(numbers)
|
return sum(numbers) / len(numbers)
|
||||||
|
|
||||||
|
|
||||||
@tool
|
@app.tool
|
||||||
def factorial(n: Annotated[int, "Non-negative integer"]) -> Annotated[int, "Factorial of n"]:
|
def factorial(n: Annotated[int, "Non-negative integer"]) -> Annotated[int, "Factorial of n"]:
|
||||||
"""Calculate the factorial of a number."""
|
"""Calculate the factorial of a number."""
|
||||||
if n < 0:
|
if n < 0:
|
||||||
|
|
@ -106,7 +79,7 @@ class PersonInfo(TypedDict):
|
||||||
is_active: bool
|
is_active: bool
|
||||||
|
|
||||||
|
|
||||||
@tool
|
@app.tool
|
||||||
def create_user_profile(
|
def create_user_profile(
|
||||||
person: Annotated[PersonInfo, "Person's information"],
|
person: Annotated[PersonInfo, "Person's information"],
|
||||||
) -> Annotated[str, "Formatted user profile"]:
|
) -> Annotated[str, "Formatted user profile"]:
|
||||||
|
|
@ -129,7 +102,7 @@ class CalculationResult(TypedDict):
|
||||||
count: int
|
count: int
|
||||||
|
|
||||||
|
|
||||||
@tool
|
@app.tool
|
||||||
def analyze_numbers(
|
def analyze_numbers(
|
||||||
values: Annotated[list[float], "List of numbers to analyze"],
|
values: Annotated[list[float], "List of numbers to analyze"],
|
||||||
) -> Annotated[CalculationResult, "Statistical analysis of the numbers"]:
|
) -> Annotated[CalculationResult, "Statistical analysis of the numbers"]:
|
||||||
|
|
@ -144,3 +117,14 @@ def analyze_numbers(
|
||||||
"max": max(values),
|
"max": max(values),
|
||||||
"count": len(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
|
### 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
|
```python
|
||||||
@app.tool
|
@app.tool
|
||||||
def my_tool(param: Annotated[str, "Description"]) -> str:
|
def my_tool(param: Annotated[str, "Description"]) -> str:
|
||||||
|
|
@ -39,6 +40,29 @@ def my_tool(param: Annotated[str, "Description"]) -> str:
|
||||||
return f"Result: {param}"
|
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
|
### 3. Running the Server
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
|
|
||||||
|
|
@ -63,4 +63,4 @@ if __name__ == "__main__":
|
||||||
app.run(transport="stdio")
|
app.run(transport="stdio")
|
||||||
else:
|
else:
|
||||||
# Default to HTTP transport
|
# 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
|
## Running the Example
|
||||||
|
|
||||||
- **Run**: `python -m arcade_mcp_server`
|
- **Run**: `uv run 03_context.py`
|
||||||
- **Run (stdio)**: `python -m arcade_mcp_server stdio`
|
- **Run (stdio)**: `uv run 03_context.py stdio`
|
||||||
- **Env**: set `API_KEY`, `DATABASE_URL`
|
- **Env**: set `API_KEY`, `DATABASE_URL`
|
||||||
|
|
||||||
## Source Code
|
## Source Code
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
03_context.py - Using Context with namespaced runtime APIs
|
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,
|
Context (provided at runtime by the TDK wrapper), including logging,
|
||||||
secrets, and progress reporting.
|
secrets, and progress reporting.
|
||||||
|
|
||||||
To run (auto-discovery):
|
To run:
|
||||||
python -m arcade_mcp_server
|
uv run 03_context.py # HTTP transport (default)
|
||||||
|
uv run 03_context.py stdio # stdio transport for Claude Desktop
|
||||||
For Claude Desktop (stdio transport):
|
|
||||||
python -m arcade_mcp_server stdio
|
|
||||||
|
|
||||||
Set environment variables for secrets:
|
Set environment variables for secrets:
|
||||||
export API_KEY="your-secret-key"
|
export API_KEY="your-secret-key"
|
||||||
export DATABASE_URL="postgresql://localhost/mydb"
|
export DATABASE_URL="postgresql://localhost/mydb"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
from typing import Annotated, Any
|
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(
|
async def secure_api_call(
|
||||||
context: Context,
|
context: Context,
|
||||||
endpoint: Annotated[str, "API endpoint to call"],
|
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]}..."
|
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(
|
async def database_info(
|
||||||
context: Context, table_name: Annotated[str | None, "Specific table to check"] = None
|
context: Context, table_name: Annotated[str | None, "Specific table to check"] = None
|
||||||
) -> Annotated[str, "Database connection info"]:
|
) -> Annotated[str, "Database connection info"]:
|
||||||
|
|
@ -71,7 +78,7 @@ async def database_info(
|
||||||
return f"{user_info}\nDatabase: {db_url}"
|
return f"{user_info}\nDatabase: {db_url}"
|
||||||
|
|
||||||
|
|
||||||
@tool
|
@app.tool
|
||||||
async def debug_context(
|
async def debug_context(
|
||||||
context: Context,
|
context: Context,
|
||||||
show_secrets: Annotated[bool, "Whether to show secret keys (not values)"] = False,
|
show_secrets: Annotated[bool, "Whether to show secret keys (not values)"] = False,
|
||||||
|
|
@ -92,7 +99,7 @@ async def debug_context(
|
||||||
return info
|
return info
|
||||||
|
|
||||||
|
|
||||||
@tool
|
@app.tool
|
||||||
async def process_with_progress(
|
async def process_with_progress(
|
||||||
context: Context,
|
context: Context,
|
||||||
items: Annotated[list[str], "Items to process"],
|
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.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.log.<level>(msg): Send log messages to the client (debug/info/warning/error)
|
||||||
# - context.progress.report(progress, total=None, message=None): Progress updates
|
# - 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
|
## Running the Example
|
||||||
|
|
||||||
- **Run**: `python -m arcade_mcp_server`
|
- **Run**: `uv run 04_secrets.py`
|
||||||
- **Run (stdio)**: `python -m arcade_mcp_server stdio`
|
- **Run (stdio)**: `uv run 04_secrets.py stdio`
|
||||||
- **Create `.env`**: Add `API_KEY=supersecret` to a `.env` file
|
- **Create `.env`**: Add `API_KEY=supersecret` to a `.env` file
|
||||||
|
|
||||||
## Source Code
|
## Source Code
|
||||||
|
|
||||||
```python
|
```python
|
||||||
--8<-- "docs/examples/04_tool_secrets.py"
|
--8<-- "docs/examples/04_secrets.py"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Working with Secrets
|
## Working with Secrets
|
||||||
|
|
@ -22,12 +22,11 @@ Secrets can be provided via environment variables:
|
||||||
```bash
|
```bash
|
||||||
export API_KEY="your-secret-key"
|
export API_KEY="your-secret-key"
|
||||||
export DATABASE_URL="postgresql://localhost/mydb"
|
export DATABASE_URL="postgresql://localhost/mydb"
|
||||||
python -m arcade_mcp_server
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. Using .env Files
|
### 2. Using .env Files
|
||||||
|
|
||||||
Create a `.env` file in your working directory:
|
Create a `.env` file in the directoryof your server:
|
||||||
```
|
```
|
||||||
API_KEY=supersecret
|
API_KEY=supersecret
|
||||||
DATABASE_URL=postgresql://user:pass@localhost/db
|
DATABASE_URL=postgresql://user:pass@localhost/db
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,28 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""04: Read secrets from .env via Context
|
"""04: Read secrets from .env via Context
|
||||||
|
|
||||||
Run (auto-discovery):
|
Run:
|
||||||
python -m arcade_mcp_server
|
uv run 04_secrets.py # HTTP transport (default)
|
||||||
|
uv run 04_secrets.py stdio # stdio transport for Claude Desktop
|
||||||
For Claude Desktop (stdio transport):
|
|
||||||
python -m arcade_mcp_server stdio
|
|
||||||
|
|
||||||
Environment:
|
Environment:
|
||||||
# Create a .env in the working directory with:
|
# Create a .env in the working directory with:
|
||||||
# API_KEY=supersecret
|
# 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(
|
@app.tool(
|
||||||
name="UseSecret",
|
|
||||||
desc="Echo a masked secret read from the context",
|
|
||||||
requires_secrets=["API_KEY"], # declare we need API_KEY
|
requires_secrets=["API_KEY"], # declare we need API_KEY
|
||||||
)
|
)
|
||||||
def use_secret(context: Context) -> str:
|
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}"
|
return f"Got API_KEY of length {len(value)} -> {masked}"
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return f"Error getting secret: {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__":
|
if __name__ == "__main__":
|
||||||
# Run the server
|
# 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
|
## 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
|
```bash
|
||||||
# Install the Arcade CLI
|
# Install the CLI
|
||||||
uv pip install arcade-mcp
|
uv pip install arcade-mcp
|
||||||
|
|
||||||
# Create a new server with example tools
|
# Create a new server project with example tools
|
||||||
arcade new my_server
|
arcade new my_server
|
||||||
cd my_server
|
cd my_server
|
||||||
|
|
||||||
# Run the server
|
# Run your server
|
||||||
arcade mcp
|
uv run server.py
|
||||||
```
|
```
|
||||||
|
|
||||||
|
This creates a complete project with `server.py`, `pyproject.toml`, and example tools showing best practices.
|
||||||
|
|
||||||
## Examples Overview
|
## Examples Overview
|
||||||
|
|
||||||
### Basic Examples
|
### Basic Examples
|
||||||
|
|
||||||
1. **[00_hello_world.py](00_hello_world.py)** – Minimal tool example
|
1. **[00_hello_world.py](00_hello_world.py)** – Minimal tool example
|
||||||
- Single `@tool` function showing the basics
|
- 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
|
2. **[01_tools.py](01_tools.py)** – Creating tools and discovery
|
||||||
- Simple parameters, lists, and `TypedDict`
|
- Simple parameters, lists, and `TypedDict`
|
||||||
- How the server discovers tools automatically
|
- 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
|
3. **[02_building_apps.py](02_building_apps.py)** – Building apps with MCPApp
|
||||||
- Create an `MCPApp`, register tools with `@app.tool`
|
- Create an `MCPApp`, register tools with `@app.tool`
|
||||||
- Run HTTP: `python 02_building_apps.py`
|
- Run HTTP: `uv run 02_building_apps.py`
|
||||||
- Run stdio: `python 02_building_apps.py stdio`
|
- Run stdio: `uv run 02_building_apps.py stdio`
|
||||||
|
|
||||||
4. **[03_context.py](03_context.py)** – Using `Context`
|
4. **[03_context.py](03_context.py)** – Using `Context`
|
||||||
- Access secrets, logging, and user 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
|
- 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
|
6. **[05_logging.py](05_logging.py)** – Logging with MCP
|
||||||
- Demonstrates debug/info/warning/error levels and structured logs
|
- 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
|
## 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
|
```bash
|
||||||
# Auto-discover tools in current directory
|
# Run any example file directly
|
||||||
arcade mcp
|
uv run 00_hello_world.py
|
||||||
|
uv run 02_building_apps.py
|
||||||
|
uv run 06_tool_organization.py
|
||||||
|
|
||||||
# With specific transport
|
# With specific transport
|
||||||
arcade mcp stdio # For Claude Desktop
|
uv run server.py stdio # For Claude Desktop
|
||||||
arcade mcp # HTTP by default
|
uv run server.py http # HTTP by default
|
||||||
|
|
||||||
# With debugging
|
# You can also run with python directly
|
||||||
arcade mcp --debug
|
python 00_hello_world.py
|
||||||
|
python 02_building_apps.py stdio
|
||||||
# With hot reload (HTTP only)
|
|
||||||
arcade mcp --reload
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Alternative: Direct Python Execution
|
All example files include proper command-line argument handling with `if __name__ == "__main__":` blocks.
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
|
||||||
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
|
# 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
|
### 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
|
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
|
### 2. Create Your Server
|
||||||
|
|
||||||
Start with a pre-configured server that includes example tools:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
arcade new my_server
|
arcade new my_server
|
||||||
cd my_server
|
cd my_server
|
||||||
```
|
```
|
||||||
|
|
||||||
This creates a starter MCP server with three example tools:
|
This generates a complete project with:
|
||||||
- **Simple tool** - A basic greeting function
|
|
||||||
- **Secret-based tool** - Demonstrates using environment secrets
|
- **server.py** - Main server file with MCPApp and example tools
|
||||||
- **OAuth tool** - Shows user authentication flow (requires `arcade login`)
|
|
||||||
|
- **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
|
### 3. Run Your Server
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Run HTTP server (default, great for development)
|
# Run with uv (recommended)
|
||||||
arcade mcp
|
uv run server.py
|
||||||
|
|
||||||
# Or run stdio server (for Claude Desktop, Cursor, etc.)
|
# Run with HTTP transport (default)
|
||||||
arcade mcp stdio
|
uv run server.py http
|
||||||
|
|
||||||
|
# Run with stdio transport (for Claude Desktop)
|
||||||
|
uv run server.py stdio
|
||||||
```
|
```
|
||||||
|
|
||||||
You should see output like:
|
You should see output like:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
DEBUG | 11:43:11 | arcade_mcp_server.mcp_app:169 | Added tool: greet
|
INFO | Starting server v1.0.0 (my_server)
|
||||||
INFO | 11:43:11 | arcade_mcp_server.mcp_app:211 | Starting server v1.0.0 with 3 tools
|
INFO | Added tool: greet
|
||||||
INFO: Started server process [89481]
|
INFO | Added tool: add_numbers
|
||||||
INFO: Waiting for application startup.
|
INFO | Starting MCP server on http://127.0.0.1:8000
|
||||||
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)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
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
|
### 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.
|
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
|
## Building MCP Servers
|
||||||
|
|
||||||
|
|
@ -109,7 +98,7 @@ from arcade_mcp_server import MCPApp
|
||||||
from typing import Annotated
|
from typing import Annotated
|
||||||
|
|
||||||
app = MCPApp(
|
app = MCPApp(
|
||||||
name="my-tools",
|
name="my_serve_",
|
||||||
version="1.0.0",
|
version="1.0.0",
|
||||||
instructions="Custom MCP server with specialized tools"
|
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)
|
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
|
```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)
|
# Tool secrets (available to tools via context)
|
||||||
MY_API_KEY="secret-value"
|
MY_API_KEY="secret-value"
|
||||||
DATABASE_URL="postgresql://..."
|
DATABASE_URL="postgresql://..."
|
||||||
|
|
@ -209,20 +139,22 @@ DATABASE_URL="postgresql://..."
|
||||||
## Development Tips
|
## Development Tips
|
||||||
|
|
||||||
### Hot Reload
|
### 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
|
```python
|
||||||
arcade mcp --reload --debug
|
app.run(host="127.0.0.1", port=8000, reload=True)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Logging
|
### Logging
|
||||||
- Use `--debug` for verbose logging
|
- Set `log_level="DEBUG"` in MCPApp for verbose logging
|
||||||
- In stdio mode, logs go to stderr
|
- In stdio mode, logs go to stderr
|
||||||
- In HTTP mode, logs go to stdout
|
- In HTTP mode, logs go to stdout
|
||||||
|
|
||||||
### Testing Tools
|
### Docs for your MCP Server
|
||||||
With HTTP transport and debug mode, access API documentation at:
|
With HTTP transport, access API documentation at:
|
||||||
|
|
||||||
- http://localhost:8000/docs (Swagger UI)
|
- http://localhost:8000/docs (Swagger UI)
|
||||||
|
|
||||||
- http://localhost:8000/redoc (ReDoc)
|
- http://localhost:8000/redoc (ReDoc)
|
||||||
|
|
||||||
## Next Steps
|
## Next Steps
|
||||||
|
|
|
||||||
|
|
@ -27,47 +27,50 @@ Arcade MCP (Model Context Protocol) enables AI assistants and development tools
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
|
|
||||||
We recommend installing the `arcade-mcp` CLI package, which includes `arcade-mcp-server` and provides a streamlined development workflow:
|
We recommend installing the `arcade-mcp-server` library for direct Python development:
|
||||||
|
|
||||||
```bash
|
|
||||||
uv pip install arcade-mcp
|
|
||||||
```
|
|
||||||
|
|
||||||
Or install just the server library if you prefer a direct Python approach:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
uv pip install arcade-mcp-server
|
uv pip install arcade-mcp-server
|
||||||
```
|
```
|
||||||
|
|
||||||
### Quick Start: Create a New Server (Recommended)
|
Or install the `arcade-mcp` CLI package for additional tooling and streamlined development workflow:
|
||||||
|
|
||||||
The fastest way to get started is with the `arcade new` command, which creates a starter MCP server with example tools:
|
|
||||||
|
|
||||||
```bash
|
```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
|
# Create a new server project
|
||||||
arcade new my_server
|
arcade new my_server
|
||||||
|
|
||||||
# Navigate to the project
|
# Navigate to the project
|
||||||
cd my_server
|
cd my_server
|
||||||
|
|
||||||
# Run the server
|
|
||||||
arcade mcp
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The generated server includes three example tools:
|
This generates a complete project with:
|
||||||
- **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`)
|
|
||||||
|
|
||||||
### 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
|
```python
|
||||||
from arcade_mcp_server import MCPApp
|
#!/usr/bin/env python3
|
||||||
|
import sys
|
||||||
from typing import Annotated
|
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
|
@app.tool
|
||||||
def greet(name: Annotated[str, "Name to greet"]) -> str:
|
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}!"
|
return f"Hello, {name}!"
|
||||||
|
|
||||||
if __name__ == "__main__":
|
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
|
### Running Your Server
|
||||||
|
|
||||||
**Recommended: Use the Arcade CLI**
|
Run your server directly with Python:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Run HTTP server (default)
|
# Run with HTTP transport (default)
|
||||||
arcade mcp
|
uv run server.py
|
||||||
|
|
||||||
# Run stdio server (for Claude Desktop, Cursor, etc.)
|
# Run with stdio transport (for Claude Desktop)
|
||||||
arcade mcp stdio
|
uv run server.py stdio
|
||||||
|
|
||||||
# Run with debug logging and hot reload
|
# Or use python directly
|
||||||
arcade mcp --debug --reload
|
python server.py http
|
||||||
|
python server.py stdio
|
||||||
```
|
```
|
||||||
|
|
||||||
**Alternative: Direct Python execution**
|
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.
|
||||||
|
|
||||||
```bash
|
|
||||||
# Run your server.py file directly
|
|
||||||
python server.py
|
|
||||||
```
|
|
||||||
|
|
||||||
### Configure MCP Clients
|
### Configure MCP Clients
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,8 @@ nav:
|
||||||
- examples/03_context.md
|
- examples/03_context.md
|
||||||
- examples/04_secrets.md
|
- examples/04_secrets.md
|
||||||
- examples/05_logging.md
|
- examples/05_logging.md
|
||||||
|
- examples/06_tool_organization.md
|
||||||
|
- examples/07_auth.md
|
||||||
- Clients:
|
- Clients:
|
||||||
- clients/claude.md
|
- clients/claude.md
|
||||||
- clients/cursor.md
|
- clients/cursor.md
|
||||||
|
|
@ -80,7 +82,6 @@ nav:
|
||||||
- clients/inspector.md
|
- clients/inspector.md
|
||||||
- API Reference:
|
- API Reference:
|
||||||
- api/mcp_app.md
|
- api/mcp_app.md
|
||||||
- api/cli.md
|
|
||||||
- Server:
|
- Server:
|
||||||
- api/server/server.md
|
- api/server/server.md
|
||||||
- api/server/middleware.md
|
- api/server/middleware.md
|
||||||
|
|
@ -88,6 +89,7 @@ nav:
|
||||||
- api/server/errors.md
|
- api/server/errors.md
|
||||||
- api/server/settings.md
|
- api/server/settings.md
|
||||||
- Advanced:
|
- Advanced:
|
||||||
|
- advanced/sharing-servers.md
|
||||||
- advanced/transports.md
|
- advanced/transports.md
|
||||||
|
|
||||||
extra:
|
extra:
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "arcade-mcp-server"
|
name = "arcade-mcp-server"
|
||||||
version = "1.0.0rc2"
|
version = "1.0.0rc3"
|
||||||
description = "Model Context Protocol (MCP) server framework for Arcade.dev"
|
description = "Model Context Protocol (MCP) server framework for Arcade.dev"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
authors = [{ name = "Arcade.dev" }]
|
authors = [{ name = "Arcade.dev" }]
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ requires-python = ">=3.10"
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
# CLI 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",
|
"arcade-core>=2.5.0rc2,<3.0.0",
|
||||||
"typer==0.10.0",
|
"typer==0.10.0",
|
||||||
"rich==13.9.4",
|
"rich==13.9.4",
|
||||||
|
|
@ -41,7 +41,7 @@ all = [
|
||||||
"pytz>=2024.1",
|
"pytz>=2024.1",
|
||||||
"python-dateutil>=2.8.2",
|
"python-dateutil>=2.8.2",
|
||||||
# mcp
|
# mcp
|
||||||
"arcade-mcp-server>=1.0.0rc2,<3.0.0",
|
"arcade-mcp-server>=1.0.0rc3,<3.0.0",
|
||||||
# serve
|
# serve
|
||||||
"arcade-serve>=2.2.0rc2,<3.0.0",
|
"arcade-serve>=2.2.0rc2,<3.0.0",
|
||||||
# tdk
|
# tdk
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue