diff --git a/README.md b/README.md index 44026c79..815cacea 100644 --- a/README.md +++ b/README.md @@ -32,16 +32,16 @@

- Documentation • - Tools • - Quickstart • + Prebuilt ToolsContact Us # Arcade MCP Server Framework -**To learn more about Arcade.dev, check out our [documentation](https://docs.arcade.dev/home).** +* **To see example servers built with Arcade MCP Server Framework (this repo), check out our [examples](examples/)** -**To learn more about the Arcade MCP Server Framework, check out our [Arcade MCP documentation](https://python.mcp.arcade.dev/)** +* **To learn more about the Arcade MCP Server Framework (this repo), check out our [Arcade MCP documentation](https://docs.arcade.dev/en/home/build-tools/create-a-mcp-server)** + +* **To learn more about other offerings from Arcade.dev, check out our [documentation](https://docs.arcade.dev/home).** _Pst. hey, you, give us a star if you like it!_ @@ -49,13 +49,13 @@ _Pst. hey, you, give us a star if you like it!_ GitHub stars -### Quick Start: Create a New Server +## Quick Start: Create a New Server -The fastest way to get started is with the `arcade new` command, which creates a complete MCP server project: +The fastest way to get started is with the `arcade new` CLI command, which creates a complete MCP server project: ```bash # Install the CLI -uv pip install arcade-mcp +uv tool install arcade-mcp # Create a new server project arcade new my_server @@ -64,7 +64,7 @@ arcade new my_server cd my_server ``` -This generates a complete project with: +This generates a project with: - **server.py** - Main server file with MCPApp and example tools @@ -72,24 +72,84 @@ This generates a complete project with: - **.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: +The generated `server.py` includes proper command-line argument handling and three example tools: ```python #!/usr/bin/env python3 +"""simple_server MCP server""" + import sys from typing import Annotated -from arcade_mcp_server import MCPApp -app = MCPApp(name="my_server", version="1.0.0") +import httpx +from arcade_mcp_server import Context, MCPApp +from arcade_mcp_server.auth import Reddit + +app = MCPApp(name="simple_server", version="1.0.0", log_level="DEBUG") + @app.tool -def greet(name: Annotated[str, "Name to greet"]) -> str: - """Greet someone by name.""" +def greet(name: Annotated[str, "The name of the person to greet"]) -> str: + """Greet a person by name.""" return f"Hello, {name}!" + +# To use this tool locally, you need to either set the secret in the .env file or as an environment variable +@app.tool(requires_secrets=["MY_SECRET_KEY"]) +def whisper_secret(context: Context) -> Annotated[str, "The last 4 characters of the secret"]: + """Reveal the last 4 characters of a secret""" + # Secrets are injected into the context at runtime. + # LLMs and MCP clients cannot see or access your secrets + # You can define secrets in a .env file. + try: + secret = context.get_secret("MY_SECRET_KEY") + except Exception as e: + return str(e) + + return "The last 4 characters of the secret are: " + secret[-4:] + +# To use this tool locally, you need to install the Arcade CLI (uv tool install arcade-mcp) +# and then 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": "{{ toolkit_name }}-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__": - transport = sys.argv[1] if len(sys.argv) > 1 else "http" + # Get transport from command line argument, default to "stdio" + # - "stdio" (default): Standard I/O for Claude Desktop, CLI tools, etc. + # Supports tools that require_auth or require_secrets out-of-the-box + # - "http": HTTPS streaming for Cursor, VS Code, etc. + # Does not support tools that require_auth or require_secrets unless the server is deployed + # using 'arcade deploy' or added in the Arcade Developer Dashboard with 'Arcade' server type + transport = sys.argv[1] if len(sys.argv) > 1 else "stdio" + + # Run the server app.run(transport=transport, host="127.0.0.1", port=8000) + ``` This approach gives you: @@ -106,11 +166,11 @@ This approach gives you: Run your server directly with Python: ```bash -# Run with HTTP transport (default) +# Run with stdio transport (default) uv run server.py -# Run with stdio transport (for Claude Desktop) -uv run server.py stdio +# Run with http transport via command line argument +uv run server.py http # Or use python directly python server.py http @@ -124,26 +184,15 @@ Your server will start and listen for connections. With HTTP transport, you can Once your server is running, connect it to your favorite AI assistant: ```bash -# Configure Claude Desktop (configures for stdio) -arcade configure claude --from-local - -# Configure Cursor (configures for http streamable) -arcade configure cursor --from-local - -# Configure VS Code (configures for http streamable) -arcade configure vscode --from-local +arcade configure claude # Configure Claude Desktop to connect to your stdio server in your current directory +arcade configure cursor --transport http --port 8080 # Configure Cursor to connect to your local HTTP server on port 8080 +arcade configure vscode --entrypoint my_server.py # Configure VSCode to connect to your stdio server that will run when my_server.py is executed directly ``` -## Client Libraries - -- **[ArcadeAI/arcade-py](https://github.com/ArcadeAI/arcade-py):** - The Python client for interacting with Arcade. - -- **[ArcadeAI/arcade-js](https://github.com/ArcadeAI/arcade-js):** - The JavaScript client for interacting with Arcade. - -- **[ArcadeAI/arcade-go](https://github.com/ArcadeAI/arcade-go):** - The Go client for interacting with Arcade. +## Installing this Repo from Source +```bash +git clone https://github.com/ArcadeAI/arcade-mcp.git && cd arcade-mcp && make install +``` ## Support and Community diff --git a/examples/agent_frameworks/ai-sdk/.env.example b/contrib/examples/ai-sdk/.env.example similarity index 100% rename from examples/agent_frameworks/ai-sdk/.env.example rename to contrib/examples/ai-sdk/.env.example diff --git a/examples/agent_frameworks/ai-sdk/.gitignore b/contrib/examples/ai-sdk/.gitignore similarity index 100% rename from examples/agent_frameworks/ai-sdk/.gitignore rename to contrib/examples/ai-sdk/.gitignore diff --git a/examples/agent_frameworks/ai-sdk/LICENSE b/contrib/examples/ai-sdk/LICENSE similarity index 100% rename from examples/agent_frameworks/ai-sdk/LICENSE rename to contrib/examples/ai-sdk/LICENSE diff --git a/examples/agent_frameworks/ai-sdk/README.md b/contrib/examples/ai-sdk/README.md similarity index 100% rename from examples/agent_frameworks/ai-sdk/README.md rename to contrib/examples/ai-sdk/README.md diff --git a/examples/agent_frameworks/ai-sdk/generateText.js b/contrib/examples/ai-sdk/generateText.js similarity index 100% rename from examples/agent_frameworks/ai-sdk/generateText.js rename to contrib/examples/ai-sdk/generateText.js diff --git a/examples/agent_frameworks/ai-sdk/index.js b/contrib/examples/ai-sdk/index.js similarity index 100% rename from examples/agent_frameworks/ai-sdk/index.js rename to contrib/examples/ai-sdk/index.js diff --git a/examples/agent_frameworks/ai-sdk/package.json b/contrib/examples/ai-sdk/package.json similarity index 100% rename from examples/agent_frameworks/ai-sdk/package.json rename to contrib/examples/ai-sdk/package.json diff --git a/examples/agent_frameworks/ai-sdk/pnpm-lock.yaml b/contrib/examples/ai-sdk/pnpm-lock.yaml similarity index 100% rename from examples/agent_frameworks/ai-sdk/pnpm-lock.yaml rename to contrib/examples/ai-sdk/pnpm-lock.yaml diff --git a/examples/agent_frameworks/crewai/crewai_with_arcade_tool.py b/contrib/examples/crewai/crewai_with_arcade_tool.py similarity index 100% rename from examples/agent_frameworks/crewai/crewai_with_arcade_tool.py rename to contrib/examples/crewai/crewai_with_arcade_tool.py diff --git a/examples/agent_frameworks/crewai/requirements.txt b/contrib/examples/crewai/requirements.txt similarity index 100% rename from examples/agent_frameworks/crewai/requirements.txt rename to contrib/examples/crewai/requirements.txt diff --git a/examples/agent_frameworks/crewai/simple_crewai_with_arcade_tool.py b/contrib/examples/crewai/simple_crewai_with_arcade_tool.py similarity index 100% rename from examples/agent_frameworks/crewai/simple_crewai_with_arcade_tool.py rename to contrib/examples/crewai/simple_crewai_with_arcade_tool.py diff --git a/examples/agent_frameworks/langchain-ts/.env.example b/contrib/examples/langchain-ts/.env.example similarity index 100% rename from examples/agent_frameworks/langchain-ts/.env.example rename to contrib/examples/langchain-ts/.env.example diff --git a/examples/agent_frameworks/langchain-ts/.gitignore b/contrib/examples/langchain-ts/.gitignore similarity index 100% rename from examples/agent_frameworks/langchain-ts/.gitignore rename to contrib/examples/langchain-ts/.gitignore diff --git a/examples/agent_frameworks/langchain-ts/LICENSE b/contrib/examples/langchain-ts/LICENSE similarity index 100% rename from examples/agent_frameworks/langchain-ts/LICENSE rename to contrib/examples/langchain-ts/LICENSE diff --git a/examples/agent_frameworks/langchain-ts/langchain-tool-arcade-auth.ts b/contrib/examples/langchain-ts/langchain-tool-arcade-auth.ts similarity index 100% rename from examples/agent_frameworks/langchain-ts/langchain-tool-arcade-auth.ts rename to contrib/examples/langchain-ts/langchain-tool-arcade-auth.ts diff --git a/examples/agent_frameworks/langchain-ts/langgraph-arcade-minimal.ts b/contrib/examples/langchain-ts/langgraph-arcade-minimal.ts similarity index 100% rename from examples/agent_frameworks/langchain-ts/langgraph-arcade-minimal.ts rename to contrib/examples/langchain-ts/langgraph-arcade-minimal.ts diff --git a/examples/agent_frameworks/langchain-ts/langgraph-with-user-auth.ts b/contrib/examples/langchain-ts/langgraph-with-user-auth.ts similarity index 100% rename from examples/agent_frameworks/langchain-ts/langgraph-with-user-auth.ts rename to contrib/examples/langchain-ts/langgraph-with-user-auth.ts diff --git a/examples/agent_frameworks/langchain-ts/langgraph.json b/contrib/examples/langchain-ts/langgraph.json similarity index 100% rename from examples/agent_frameworks/langchain-ts/langgraph.json rename to contrib/examples/langchain-ts/langgraph.json diff --git a/examples/agent_frameworks/langchain-ts/package-lock.json b/contrib/examples/langchain-ts/package-lock.json similarity index 100% rename from examples/agent_frameworks/langchain-ts/package-lock.json rename to contrib/examples/langchain-ts/package-lock.json diff --git a/examples/agent_frameworks/langchain-ts/package.json b/contrib/examples/langchain-ts/package.json similarity index 100% rename from examples/agent_frameworks/langchain-ts/package.json rename to contrib/examples/langchain-ts/package.json diff --git a/examples/agent_frameworks/langchain-ts/pnpm-lock.yaml b/contrib/examples/langchain-ts/pnpm-lock.yaml similarity index 100% rename from examples/agent_frameworks/langchain-ts/pnpm-lock.yaml rename to contrib/examples/langchain-ts/pnpm-lock.yaml diff --git a/examples/agent_frameworks/langchain-ts/tsconfig.json b/contrib/examples/langchain-ts/tsconfig.json similarity index 100% rename from examples/agent_frameworks/langchain-ts/tsconfig.json rename to contrib/examples/langchain-ts/tsconfig.json diff --git a/examples/agent_frameworks/langchain/langchain_tool_arcade_auth.py b/contrib/examples/langchain/langchain_tool_arcade_auth.py similarity index 100% rename from examples/agent_frameworks/langchain/langchain_tool_arcade_auth.py rename to contrib/examples/langchain/langchain_tool_arcade_auth.py diff --git a/examples/agent_frameworks/langchain/langgraph_arcade_minimal.py b/contrib/examples/langchain/langgraph_arcade_minimal.py similarity index 100% rename from examples/agent_frameworks/langchain/langgraph_arcade_minimal.py rename to contrib/examples/langchain/langgraph_arcade_minimal.py diff --git a/examples/agent_frameworks/langchain/langgraph_with_user_auth.py b/contrib/examples/langchain/langgraph_with_user_auth.py similarity index 100% rename from examples/agent_frameworks/langchain/langgraph_with_user_auth.py rename to contrib/examples/langchain/langgraph_with_user_auth.py diff --git a/examples/agent_frameworks/langchain/requirements.txt b/contrib/examples/langchain/requirements.txt similarity index 100% rename from examples/agent_frameworks/langchain/requirements.txt rename to contrib/examples/langchain/requirements.txt diff --git a/examples/agent_frameworks/langchain/studio/README.md b/contrib/examples/langchain/studio/README.md similarity index 100% rename from examples/agent_frameworks/langchain/studio/README.md rename to contrib/examples/langchain/studio/README.md diff --git a/examples/agent_frameworks/langchain/studio/configuration.py b/contrib/examples/langchain/studio/configuration.py similarity index 100% rename from examples/agent_frameworks/langchain/studio/configuration.py rename to contrib/examples/langchain/studio/configuration.py diff --git a/examples/agent_frameworks/langchain/studio/env.example b/contrib/examples/langchain/studio/env.example similarity index 100% rename from examples/agent_frameworks/langchain/studio/env.example rename to contrib/examples/langchain/studio/env.example diff --git a/examples/agent_frameworks/langchain/studio/graph.py b/contrib/examples/langchain/studio/graph.py similarity index 100% rename from examples/agent_frameworks/langchain/studio/graph.py rename to contrib/examples/langchain/studio/graph.py diff --git a/examples/agent_frameworks/langchain/studio/langgraph.json b/contrib/examples/langchain/studio/langgraph.json similarity index 100% rename from examples/agent_frameworks/langchain/studio/langgraph.json rename to contrib/examples/langchain/studio/langgraph.json diff --git a/examples/agent_frameworks/langchain/studio/requirements.txt b/contrib/examples/langchain/studio/requirements.txt similarity index 100% rename from examples/agent_frameworks/langchain/studio/requirements.txt rename to contrib/examples/langchain/studio/requirements.txt diff --git a/examples/agent_frameworks/langgraph-ts/.gitignore b/contrib/examples/langgraph-ts/.gitignore similarity index 100% rename from examples/agent_frameworks/langgraph-ts/.gitignore rename to contrib/examples/langgraph-ts/.gitignore diff --git a/examples/agent_frameworks/langgraph-ts/README.md b/contrib/examples/langgraph-ts/README.md similarity index 100% rename from examples/agent_frameworks/langgraph-ts/README.md rename to contrib/examples/langgraph-ts/README.md diff --git a/examples/agent_frameworks/langgraph-ts/langgraph.json b/contrib/examples/langgraph-ts/langgraph.json similarity index 100% rename from examples/agent_frameworks/langgraph-ts/langgraph.json rename to contrib/examples/langgraph-ts/langgraph.json diff --git a/examples/agent_frameworks/langgraph-ts/package.json b/contrib/examples/langgraph-ts/package.json similarity index 100% rename from examples/agent_frameworks/langgraph-ts/package.json rename to contrib/examples/langgraph-ts/package.json diff --git a/examples/agent_frameworks/langgraph-ts/src/configuration.ts b/contrib/examples/langgraph-ts/src/configuration.ts similarity index 100% rename from examples/agent_frameworks/langgraph-ts/src/configuration.ts rename to contrib/examples/langgraph-ts/src/configuration.ts diff --git a/examples/agent_frameworks/langgraph-ts/src/graph.ts b/contrib/examples/langgraph-ts/src/graph.ts similarity index 100% rename from examples/agent_frameworks/langgraph-ts/src/graph.ts rename to contrib/examples/langgraph-ts/src/graph.ts diff --git a/examples/agent_frameworks/langgraph-ts/src/prompts.ts b/contrib/examples/langgraph-ts/src/prompts.ts similarity index 100% rename from examples/agent_frameworks/langgraph-ts/src/prompts.ts rename to contrib/examples/langgraph-ts/src/prompts.ts diff --git a/examples/agent_frameworks/langgraph-ts/studio.png b/contrib/examples/langgraph-ts/studio.png similarity index 100% rename from examples/agent_frameworks/langgraph-ts/studio.png rename to contrib/examples/langgraph-ts/studio.png diff --git a/examples/agent_frameworks/mastra/.env.example b/contrib/examples/mastra/.env.example similarity index 100% rename from examples/agent_frameworks/mastra/.env.example rename to contrib/examples/mastra/.env.example diff --git a/examples/agent_frameworks/mastra/.gitignore b/contrib/examples/mastra/.gitignore similarity index 100% rename from examples/agent_frameworks/mastra/.gitignore rename to contrib/examples/mastra/.gitignore diff --git a/examples/agent_frameworks/mastra/LICENSE b/contrib/examples/mastra/LICENSE similarity index 100% rename from examples/agent_frameworks/mastra/LICENSE rename to contrib/examples/mastra/LICENSE diff --git a/examples/agent_frameworks/mastra/README.md b/contrib/examples/mastra/README.md similarity index 100% rename from examples/agent_frameworks/mastra/README.md rename to contrib/examples/mastra/README.md diff --git a/examples/agent_frameworks/mastra/package.json b/contrib/examples/mastra/package.json similarity index 100% rename from examples/agent_frameworks/mastra/package.json rename to contrib/examples/mastra/package.json diff --git a/examples/agent_frameworks/mastra/pnpm-lock.yaml b/contrib/examples/mastra/pnpm-lock.yaml similarity index 100% rename from examples/agent_frameworks/mastra/pnpm-lock.yaml rename to contrib/examples/mastra/pnpm-lock.yaml diff --git a/examples/agent_frameworks/mastra/src/mastra/agents/gmail.ts b/contrib/examples/mastra/src/mastra/agents/gmail.ts similarity index 100% rename from examples/agent_frameworks/mastra/src/mastra/agents/gmail.ts rename to contrib/examples/mastra/src/mastra/agents/gmail.ts diff --git a/examples/agent_frameworks/mastra/src/mastra/agents/inboxTravelSearch.ts b/contrib/examples/mastra/src/mastra/agents/inboxTravelSearch.ts similarity index 100% rename from examples/agent_frameworks/mastra/src/mastra/agents/inboxTravelSearch.ts rename to contrib/examples/mastra/src/mastra/agents/inboxTravelSearch.ts diff --git a/examples/agent_frameworks/mastra/src/mastra/index.ts b/contrib/examples/mastra/src/mastra/index.ts similarity index 100% rename from examples/agent_frameworks/mastra/src/mastra/index.ts rename to contrib/examples/mastra/src/mastra/index.ts diff --git a/examples/agent_frameworks/mastra/src/mastra/tools/flightSearchTools.ts b/contrib/examples/mastra/src/mastra/tools/flightSearchTools.ts similarity index 100% rename from examples/agent_frameworks/mastra/src/mastra/tools/flightSearchTools.ts rename to contrib/examples/mastra/src/mastra/tools/flightSearchTools.ts diff --git a/examples/agent_frameworks/mastra/src/mastra/tools/gmailTools.ts b/contrib/examples/mastra/src/mastra/tools/gmailTools.ts similarity index 100% rename from examples/agent_frameworks/mastra/src/mastra/tools/gmailTools.ts rename to contrib/examples/mastra/src/mastra/tools/gmailTools.ts diff --git a/examples/agent_frameworks/mastra/src/mastra/tools/hotelSearchTools.ts b/contrib/examples/mastra/src/mastra/tools/hotelSearchTools.ts similarity index 100% rename from examples/agent_frameworks/mastra/src/mastra/tools/hotelSearchTools.ts rename to contrib/examples/mastra/src/mastra/tools/hotelSearchTools.ts diff --git a/examples/agent_frameworks/mastra/tsconfig.json b/contrib/examples/mastra/tsconfig.json similarity index 100% rename from examples/agent_frameworks/mastra/tsconfig.json rename to contrib/examples/mastra/tsconfig.json diff --git a/examples/agent_frameworks/openai-agents-ts/.env.example b/contrib/examples/openai-agents-ts/.env.example similarity index 100% rename from examples/agent_frameworks/openai-agents-ts/.env.example rename to contrib/examples/openai-agents-ts/.env.example diff --git a/examples/agent_frameworks/openai-agents-ts/.gitignore b/contrib/examples/openai-agents-ts/.gitignore similarity index 100% rename from examples/agent_frameworks/openai-agents-ts/.gitignore rename to contrib/examples/openai-agents-ts/.gitignore diff --git a/examples/agent_frameworks/openai-agents-ts/LICENSE b/contrib/examples/openai-agents-ts/LICENSE similarity index 100% rename from examples/agent_frameworks/openai-agents-ts/LICENSE rename to contrib/examples/openai-agents-ts/LICENSE diff --git a/examples/agent_frameworks/openai-agents-ts/README.md b/contrib/examples/openai-agents-ts/README.md similarity index 100% rename from examples/agent_frameworks/openai-agents-ts/README.md rename to contrib/examples/openai-agents-ts/README.md diff --git a/examples/agent_frameworks/openai-agents-ts/package-lock.json b/contrib/examples/openai-agents-ts/package-lock.json similarity index 100% rename from examples/agent_frameworks/openai-agents-ts/package-lock.json rename to contrib/examples/openai-agents-ts/package-lock.json diff --git a/examples/agent_frameworks/openai-agents-ts/package.json b/contrib/examples/openai-agents-ts/package.json similarity index 100% rename from examples/agent_frameworks/openai-agents-ts/package.json rename to contrib/examples/openai-agents-ts/package.json diff --git a/examples/agent_frameworks/openai-agents-ts/src/index.ts b/contrib/examples/openai-agents-ts/src/index.ts similarity index 100% rename from examples/agent_frameworks/openai-agents-ts/src/index.ts rename to contrib/examples/openai-agents-ts/src/index.ts diff --git a/examples/agent_frameworks/openai-agents-ts/src/waitForCompletion.ts b/contrib/examples/openai-agents-ts/src/waitForCompletion.ts similarity index 100% rename from examples/agent_frameworks/openai-agents-ts/src/waitForCompletion.ts rename to contrib/examples/openai-agents-ts/src/waitForCompletion.ts diff --git a/examples/.gitignore b/examples/.gitignore deleted file mode 100644 index 2edb4a25..00000000 --- a/examples/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# Un-ignore poetry.lock because the projects in this directory represent runnable sample apps -!poetry.lock diff --git a/examples/clients/call_a_tool_directly.py b/examples/clients/call_a_tool_directly.py deleted file mode 100644 index c913783e..00000000 --- a/examples/clients/call_a_tool_directly.py +++ /dev/null @@ -1,40 +0,0 @@ -""" -This example demonstrates how to directly call a tool that does not require authorization. -""" - -from arcadepy import Arcade # pip install arcade-py - - -def call_non_auth_tool(client: Arcade, user_id: str) -> None: - """Directly call a prebuilt tool that does not require authorization. - - In this example, we are - 1. Preparing the inputs to the Math.Add tool - 2. Executing the tool - 3. Printing the output of the tool's execution, i.e., the result of adding 9001 and 42 - - This is a simple example of calling a non-auth tool. Next, try writing your own non-auth tool for your own use case. - """ - # Prepare the inputs to the tool as a dictionary where keys are the names of the parameters expected by the tool and the values are the actual values to pass to the tool - tool_input = {"a": 9001, "b": 42} - - # Execute the tool - response = client.tools.execute( - tool_name="Math.Add", - input=tool_input, - user_id=user_id, - ) - - # Print the output of the tool execution - print(response.output.value) - - -if __name__ == "__main__": - cloud_host = "https://api.arcade.dev" - - client = Arcade( - base_url=cloud_host, # Alternatively, use http://localhost:9099 if you are running Arcade Engine locally, or any base_url if you're hosting elsewhere - ) - - user_id = "you@example.com" - call_non_auth_tool(client, user_id) diff --git a/examples/clients/call_a_tool_directly_with_auth.py b/examples/clients/call_a_tool_directly_with_auth.py deleted file mode 100644 index 333b5874..00000000 --- a/examples/clients/call_a_tool_directly_with_auth.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -This example demonstrates how to directly call a tool that requires authorization. -""" - -from arcadepy import Arcade # pip install arcade-py - - -def call_auth_tool(client: Arcade, user_id: str) -> None: - """Directly call a prebuilt tool that requires authorization. - - In this example, we are - 1. Authorizing Arcade to read emails from the user's Gmail account with the user's permission to do so - 2. Reading 5 emails from the user's Gmail account - 3. Printing the emails - - Try altering this example to call a tool that requires a different authorization. - """ - # Start the authorization process - auth_response = client.tools.authorize( - tool_name="Gmail.ListEmails", - user_id=user_id, - ) - - # If not already authorized, then wait for the user to authorize the permissions required by the tool - if auth_response.status != "completed": - print(f"Click this link to authorize: {auth_response.url}") - - # Wait for the user to complete the auth flow, if necessary - client.auth.wait_for_completion(auth_response) - - # Prepare the inputs to the tool as a dictionary where keys are the names of the parameters expected by the tool and the values are the actual values to pass to the tool - tool_input = {"n_emails": 5} - - # Execute the tool - response = client.tools.execute( - tool_name="Gmail.ListEmails", - input=tool_input, - user_id=user_id, - ) - - # Print the output of the tool execution. - print(response) - - -if __name__ == "__main__": - client = Arcade( - base_url="https://api.arcade.dev", # Alternatively, use http://localhost:9099 if you are running Arcade Engine locally, or any base_url if you're hosting elsewhere - ) - - user_id = "you@example.com" - call_auth_tool(client, user_id) diff --git a/examples/clients/call_a_tool_with_llm.py b/examples/clients/call_a_tool_with_llm.py deleted file mode 100644 index 1d8e18e6..00000000 --- a/examples/clients/call_a_tool_with_llm.py +++ /dev/null @@ -1,45 +0,0 @@ -""" -This example shows how to call a tool that requires authorization with an LLM using the OpenAI Python client. -""" - -import os - -from openai import OpenAI - - -def call_tool_with_openai(client: OpenAI) -> dict: - response = client.chat.completions.create( - messages=[ - {"role": "user", "content": "Star the ArcadeAI/arcade-mcp repository."}, - ], - model="gpt-4o-mini", # TODO: Try "claude-3-5-sonnet-20240620" or other models from our supported model providers. Checkout out our docs for a full list https://docs.arcade.dev - user="you@example.com", - tools=["Github.SetStarred"], - tool_choice="generate", # TODO: Try "execute" and note any differences - ) - - return response - - -if __name__ == "__main__": - arcade_api_key = os.environ.get( - "ARCADE_API_KEY" - ) # If you forget your Arcade API key, it is stored at ~/.arcade/credentials.yaml on `arcade login` - cloud_host = "https://api.arcade.dev" + "/v1" - - openai_client = OpenAI( - api_key=arcade_api_key, - base_url=cloud_host, # Alternatively, use http://localhost:9099/v1 if you are running Arcade Engine locally - ) - - chat_result = call_tool_with_openai(openai_client) - # If the tool call requires authorization, then wait for the user to authorize and then call the tool again - if ( - chat_result.choices[0].tool_authorizations - and chat_result.choices[0].tool_authorizations[0].get("status") == "pending" - ): - print(chat_result.choices[0].message.content) - input("After you have authorized, press Enter to continue...") - chat_result = call_tool_with_openai(openai_client) - - print(chat_result.choices[0].message.content) diff --git a/examples/clients/get_auth_token.py b/examples/clients/get_auth_token.py deleted file mode 100644 index 9840c5f8..00000000 --- a/examples/clients/get_auth_token.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -This example demonstrates how to get an authorization token for a user and then use it to make a request to the Google API on behalf of the user. -""" - -from arcadepy import Arcade -from google.oauth2.credentials import Credentials # pip install google-auth -from googleapiclient.discovery import build # pip install google-api-python-client - - -def get_auth_token(client: Arcade, user_id: str) -> str: - """Get an authorization token for a user. - - In this example, we are - 1. Starting the authorization process for the Gmail Readonly scope - 2. Waiting for the user to authorize the scope - 3. Getting the authorization token - 4. Using the authorization token to make a request to the Google API on behalf of the user - """ - # Start the authorization process - auth_response = client.auth.start( - user_id, "google", scopes=["https://www.googleapis.com/auth/gmail.readonly"] - ) - - if auth_response.status != "completed": - print(f"Click this link to authorize: {auth_response.url}") - auth_response = client.auth.wait_for_completion(auth_response) - - return auth_response.context.token - - -def use_auth_token(token: str) -> None: - """Use an authorization token to make a request to the Google API on behalf of a user. - - In this example, we are - 1. Using the authorization token that we got from the authorization process to make a request to the Google API - client.auth.wait_for_completion(auth_response) - """ - # Use the token from the authorization response - creds = Credentials(token) - service = build("gmail", "v1", credentials=creds) - - # Now you can use the Google API - results = service.users().labels().list(userId="me").execute() - labels = results.get("labels", []) - print("Labels:", labels) - - -if __name__ == "__main__": - cloud_host = "https://api.arcade.dev" - - client = Arcade( - base_url=cloud_host, # Alternatively, use http://localhost:9099 if you are running Arcade locally, or any base_url if you're hosting elsewhere - ) - - user_id = "you@example.com" - - token = get_auth_token(client, user_id) - use_auth_token(token) diff --git a/examples/serving_tools/docker/Dockerfile b/examples/serving_tools/docker/Dockerfile deleted file mode 100644 index 3267cd9d..00000000 --- a/examples/serving_tools/docker/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -ARG VERSION=latest - -# Base worker image -FROM ghcr.io/arcadeai/worker-base:${VERSION} - -# Copy requirements and constraints -COPY toolkits.txt ./ - -# Install toolkits from file -RUN pip install -r toolkits.txt diff --git a/examples/serving_tools/docker/README.md b/examples/serving_tools/docker/README.md deleted file mode 100644 index 1a67fddd..00000000 --- a/examples/serving_tools/docker/README.md +++ /dev/null @@ -1,30 +0,0 @@ -## Custom Worker Image - -This example shows how to build a custom worker image with toolkits. - -### Requirements - -- Docker - -### Build - -``` -docker build -t custom-worker:0.1.0 . -``` - -### Run - -``` -docker run -p 8002:8002 custom-worker:0.1.0 -``` - -### Change the Toolkits - -To change the toolkits, edit the `toolkits.txt` file. - -``` -arcade-gmail==0.1.0 -arcade-firecrawl==0.1.0 -arcade-zoom==0.1.2 -... -``` diff --git a/examples/serving_tools/docker/toolkits.txt b/examples/serving_tools/docker/toolkits.txt deleted file mode 100644 index c2fc264c..00000000 --- a/examples/serving_tools/docker/toolkits.txt +++ /dev/null @@ -1 +0,0 @@ -arcade-gmail diff --git a/examples/serving_tools/modal/README.md b/examples/serving_tools/modal/README.md deleted file mode 100644 index 69907ff4..00000000 --- a/examples/serving_tools/modal/README.md +++ /dev/null @@ -1,17 +0,0 @@ -## Deploy a Custom Arcade Worker on Modal - -### Requirements - -- Python 3.10+ -- Modal CLI - -### Deploy - -```bash -cd examples/serving-tools -modal deploy run-arcade-worker.py -``` - -### Changing the Toolkits - -To change the toolkits, edit the `toolkits` list in the `run-arcade-worker.py` file. diff --git a/examples/serving_tools/modal/run-arcade-worker.py b/examples/serving_tools/modal/run-arcade-worker.py deleted file mode 100644 index d7bd0f4f..00000000 --- a/examples/serving_tools/modal/run-arcade-worker.py +++ /dev/null @@ -1,34 +0,0 @@ -import os - -from modal import App, Image, asgi_app - -# Define the FastAPI app -app = App("arcade-worker") - -toolkits = ["arcade_gmail", "arcade_slack"] - -image = ( - Image.debian_slim().pip_install("arcade_tdk").pip_install("arcade_serve").pip_install(toolkits) -) - - -@app.function(image=image) -@asgi_app() -def fastapi_app(): - from arcade_serve.fastapi.worker import FastAPIWorker - from arcade_tdk import Toolkit - from fastapi import FastAPI - - web_app = FastAPI() - - # Initialize app and Arcade FastAPIWorker - worker_secret = os.environ.get("ARCADE_WORKER_SECRET", "dev") - worker = FastAPIWorker(web_app, secret=worker_secret) - - # Register toolkits we've installed - installed_toolkits = Toolkit.find_all_arcade_toolkits() - for toolkit in installed_toolkits: - if toolkit.package_name in toolkits: - worker.register_toolkit(toolkit) - - return web_app diff --git a/libs/arcade-cli/README.md b/libs/arcade-cli/README.md index 24e6270d..a9ae83b5 100644 --- a/libs/arcade-cli/README.md +++ b/libs/arcade-cli/README.md @@ -14,7 +14,7 @@ Arcade CLI provides a comprehensive command-line interface for the Arcade platfo ## Installation ```bash -pip install arcade-mcp +uv tool install arcade-mcp ``` ## Usage diff --git a/libs/arcade-cli/arcade_cli/main.py b/libs/arcade-cli/arcade_cli/main.py index 7bafa33e..fedd9361 100644 --- a/libs/arcade-cli/arcade_cli/main.py +++ b/libs/arcade-cli/arcade_cli/main.py @@ -531,7 +531,7 @@ def configure( Examples: arcade configure claude arcade configure cursor --transport http --port 8080 - arcade configure vscode --host arcade --entrypoint ../../../mcp/server.py --config .vscode/mcp.json + arcade configure vscode --host arcade --entrypoint my_server.py --config .vscode/mcp.json arcade configure claude --host local --name my_server_name """ from arcade_cli.configure import configure_client diff --git a/libs/arcade-cli/arcade_cli/templates/minimal/{{ toolkit_name }}/server.py b/libs/arcade-cli/arcade_cli/templates/minimal/{{ toolkit_name }}/server.py index a438db09..0417dfaa 100644 --- a/libs/arcade-cli/arcade_cli/templates/minimal/{{ toolkit_name }}/server.py +++ b/libs/arcade-cli/arcade_cli/templates/minimal/{{ toolkit_name }}/server.py @@ -17,7 +17,7 @@ def greet(name: Annotated[str, "The name of the person to greet"]) -> str: return f"Hello, {name}!" -# To use this tool, you need to either set the secret in the .env file or as an environment variable +# To use this tool locally, you need to either set the secret in the .env file or as an environment variable @app.tool(requires_secrets=["MY_SECRET_KEY"]) def whisper_secret(context: Context) -> Annotated[str, "The last 4 characters of the secret"]: """Reveal the last 4 characters of a secret""" @@ -31,8 +31,8 @@ def whisper_secret(context: Context) -> Annotated[str, "The last 4 characters of return "The last 4 characters of the secret are: " + secret[-4:] -# To use this tool, you need to either set your ARCADE_API_KEY as an environment variable or -# use the Arcade CLI (uv pip install arcade-mcp) and run 'arcade login' to authenticate. +# To use this tool locally, you need to install the Arcade CLI (uv tool install arcade-mcp) +# and then 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"]