-
Notifications
You must be signed in to change notification settings - Fork 14
Adds 3 new docs #506
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Adds 3 new docs #506
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
9901c63
adding the server tools to the build docs
nearestnabors 54b21f4
adding organization to nav
nearestnabors 94b2fda
adding organization to nav
nearestnabors e396331
adds loggign
nearestnabors a402e7a
fixing nav
nearestnabors e4167ff
update file name
nearestnabors 0a684aa
renaming the quickstart
nearestnabors 0771075
reformatting the quickstart
nearestnabors 3af7e78
add transport modes to glossary
nearestnabors b3d3bfb
Update app/en/home/build-tools/organize-mcp-server-tools/page.mdx
nearestnabors dbf60f3
Update app/en/home/build-tools/organize-mcp-server-tools/page.mdx
nearestnabors 9d8964f
moving shared to on-prem
nearestnabors a5b23ed
adding lost tool page
nearestnabors 3a26606
Merge branch 'main' into mcp-p1-rln
nearestnabors 44b7789
Update app/en/home/quickstart/page.mdx
nearestnabors 158d3bb
Update app/en/home/quickstart/page.mdx
nearestnabors 14549cf
Update app/en/home/quickstart/page.mdx
nearestnabors d5bc681
Update app/en/home/quickstart/page.mdx
nearestnabors 4b58f21
Update app/en/home/quickstart/page.mdx
nearestnabors 40176da
addressing Sterling's corrections from https://arcade-ai.slack.com/ar…
nearestnabors File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
333 changes: 333 additions & 0 deletions
333
app/en/home/build-tools/logging-mcp-tool-activity/page.mdx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,333 @@ | ||
| --- | ||
| title: "Logging tool activity" | ||
| description: "Learn how to log tool activity in your MCP server" | ||
| --- | ||
|
|
||
| import { Steps, Tabs, Callout } from "nextra/components"; | ||
|
|
||
| # Logging tool activity | ||
|
|
||
| <GuideOverview> | ||
| <GuideOverview.Outcomes> | ||
|
|
||
| Learn how to log tool activity in your MCP server with various levels and patterns available through the MCP protocol for debugging and monitoring. Jump to [Example Code](#example-code) to see the complete code. | ||
|
|
||
| </GuideOverview.Outcomes> | ||
|
|
||
| <GuideOverview.Prerequisites> | ||
|
|
||
| - [Arcade account](https://api.arcade.dev/signup) | ||
| - [Arcade CLI](/home/quickstart) | ||
| - [An MCP Server](/home/build-tools/create-a-mcp-server) | ||
| - [uv package manager](https://docs.astral.sh/uv/getting-started/installation/) | ||
|
|
||
| </GuideOverview.Prerequisites> | ||
|
|
||
| <GuideOverview.YouWillLearn> | ||
|
|
||
| - How to log tool activity in your MCP server with various levels and patterns for debugging and monitoring. | ||
|
|
||
| </GuideOverview.YouWillLearn> | ||
| </GuideOverview> | ||
|
|
||
| ## Log Levels | ||
|
|
||
| MCP supports standard log levels including debug, info, warning, and error: | ||
|
|
||
| ```python | ||
| await context.log.debug("Detailed debugging information") | ||
| await context.log.info("General information") | ||
| await context.log.warning("Warning messages") | ||
| await context.log.error("Error messages") | ||
| ``` | ||
|
|
||
| ## Structured Logging | ||
|
|
||
| Log with context and metadata: | ||
|
|
||
| ```python | ||
| # Include user context | ||
| await context.log.info( | ||
| f"Action performed by user: {context.user_id}" | ||
| ) | ||
|
|
||
| # Add operation details | ||
| await context.log.debug( | ||
| f"Processing {item_count} items with options: {options}" | ||
| ) | ||
| ``` | ||
|
|
||
| ## Error Logging | ||
|
|
||
| Proper error handling and logging is important for debugging and monitoring. When an error occurs, you should log the error with the type and message, and log the traceback at debug level like this: | ||
|
|
||
| ```python | ||
| try: | ||
| # Operation that might fail | ||
| result = risky_operation() | ||
| except Exception as e: | ||
| # Log error with type and message | ||
| await context.log.error( | ||
| f"Operation failed: {type(e).__name__}: {str(e)}" | ||
| ) | ||
|
|
||
| # Log traceback at debug level | ||
| await context.log.debug( | ||
| f"Traceback:\n{traceback.format_exc()}" | ||
| ) | ||
| ``` | ||
|
|
||
| ## Progress Logging for Long-Running Operations | ||
|
|
||
| Track long-running operations with progress updates like this: | ||
|
|
||
| ```python | ||
| for i, item in enumerate(items): | ||
| # Log progress | ||
| await context.log.debug( | ||
| f"Progress: {i+1}/{len(items)} ({(i+1)/len(items)*100:.0f}%)" | ||
| ) | ||
|
|
||
| # Process item | ||
| process(item) | ||
| ``` | ||
|
|
||
| ## Batch Processing | ||
|
|
||
| Log batch operations effectively by logging both individual items at debug level and a summary at info level like this: | ||
|
|
||
| ```python | ||
| # Log batch start | ||
| await context.log.info(f"Starting batch of {count} items") | ||
|
|
||
| # Log individual items at debug level | ||
| for item in items: | ||
| await context.log.debug(f"Processing: {item}") | ||
|
|
||
| # Log summary | ||
| await context.log.info( | ||
| f"Batch complete: {success_count} successful, {fail_count} failed" | ||
| ) | ||
| ``` | ||
|
|
||
| ## Best Practices | ||
|
|
||
| 1. **Use Appropriate Levels**: Debug for details, info for general flow, warning for issues, error for failures | ||
| 2. **Include Context**: Always include relevant context like user ID, operation names, counts | ||
| 3. **Structure Messages**: Use consistent message formats for easier parsing | ||
| 4. **Handle Errors Gracefully**: Log errors with enough detail to debug but not expose sensitive data | ||
| 5. **Progress Updates**: For long operations, provide regular progress updates | ||
| 6. **Batch Summaries**: For batch operations, log both individual items (debug) and summaries (info) | ||
| 7. **Performance Considerations**: Be mindful of log volume in production environments | ||
|
|
||
| ## Key Concepts | ||
|
|
||
| ## Example Code | ||
|
|
||
| ```python filename="logging.py" | ||
| #!/usr/bin/env python | ||
|
|
||
| import asyncio | ||
| import time | ||
| import traceback | ||
| from typing import Annotated, Optional | ||
|
|
||
| from arcade_mcp_server import Context, MCPApp | ||
|
|
||
| # Create the app with debug logging | ||
| app = MCPApp(name="logging_examples", version="0.1.0", log_level="DEBUG") | ||
|
|
||
|
|
||
| @app.tool | ||
| async def demonstrate_log_levels( | ||
| context: Context, message: Annotated[str, "Base message to log at different levels"] | ||
| ) -> Annotated[dict, "Summary of logged messages"]: | ||
| """Demonstrate all MCP logging levels.""" | ||
|
|
||
| # Log at each level | ||
| levels = ["debug", "info", "warning", "error"] | ||
| logged = {} | ||
|
|
||
| for level in levels: | ||
| log_message = f"[{level.upper()}] {message}" | ||
| await context.log(level, log_message) | ||
| logged[level] = log_message | ||
|
|
||
| return {"logged_messages": logged, "note": "Check your MCP client to see these messages"} | ||
|
|
||
|
|
||
| @app.tool | ||
| async def timed_operation( | ||
| context: Context, | ||
| operation_name: Annotated[str, "Name of the operation"], | ||
| duration_seconds: Annotated[float, "How long the operation takes"] = 2.0, | ||
| ) -> Annotated[dict, "Operation timing details"]: | ||
| """Perform a timed operation with detailed logging.""" | ||
|
|
||
| start_time = time.time() | ||
|
|
||
| # Log operation start | ||
| await context.log.info( | ||
| f"Starting operation: {operation_name} (expected duration: {duration_seconds}s)" | ||
| ) | ||
|
|
||
| # Simulate work with progress logging | ||
| steps = 5 | ||
| for i in range(steps): | ||
| await context.log.debug(f"Progress: step {i + 1}/{steps} ({(i + 1) / steps * 100:.0f}%)") | ||
|
|
||
| await asyncio.sleep(duration_seconds / steps) | ||
|
|
||
| # Calculate results | ||
| end_time = time.time() | ||
| actual_duration = end_time - start_time | ||
|
|
||
| # Log completion | ||
| await context.log.info(f"Completed operation: {operation_name} in {actual_duration:.2f}s") | ||
|
|
||
| return { | ||
| "operation": operation_name, | ||
| "expected_duration": duration_seconds, | ||
| "actual_duration": round(actual_duration, 2), | ||
| "start_time": start_time, | ||
| "end_time": end_time, | ||
| } | ||
|
|
||
|
|
||
| @app.tool | ||
| async def error_handling_example( | ||
| context: Context, | ||
| should_fail: Annotated[bool, "Whether to simulate an error"], | ||
| error_type: Annotated[str, "Type of error to simulate"] = "ValueError", | ||
| ) -> Annotated[dict, "Result or error details"]: | ||
| """Demonstrate error logging and handling.""" | ||
|
|
||
| try: | ||
| await context.log.debug(f"Error handling test: should_fail={should_fail}") | ||
|
|
||
| if should_fail: | ||
| if error_type == "ValueError": | ||
| raise ValueError("This is a simulated value error") # noqa: TRY301 | ||
| elif error_type == "KeyError": | ||
| raise KeyError("missing_key") # noqa: TRY301 | ||
| elif error_type == "ZeroDivisionError": | ||
| result = 1 / 0 | ||
| return {"result": result} | ||
| else: | ||
| raise Exception(f"Generic error of type: {error_type}") # noqa: TRY002, TRY301 | ||
|
|
||
| # Success case | ||
| await context.log.info("Operation completed successfully") | ||
|
|
||
| except Exception as e: | ||
| # Log the error with details | ||
| await context.log.error(f"Operation failed with {type(e).__name__}: {e!s}") | ||
|
|
||
| # Log traceback separately at debug level | ||
| await context.log.debug(f"Traceback:\n{traceback.format_exc()}") | ||
|
|
||
| return { | ||
| "status": "error", | ||
| "error_type": type(e).__name__, | ||
| "error_message": str(e), | ||
| "handled": True, | ||
| } | ||
| else: | ||
| return {"status": "success", "message": "No errors occurred"} | ||
|
|
||
|
|
||
| @app.tool | ||
| async def structured_logging( | ||
| context: Context, | ||
| user_action: Annotated[str, "Action the user is performing"], | ||
| metadata: Annotated[dict | None, "Additional metadata to log"] = None, | ||
| ) -> Annotated[str, "Confirmation message"]: | ||
| """Demonstrate structured logging patterns.""" | ||
|
|
||
| # Log main action | ||
| await context.log.info( | ||
| f"User action: {user_action} (user_id: {context.user_id or 'anonymous'})" | ||
| ) | ||
|
|
||
| # Log additional details at debug level | ||
| await context.log.debug( | ||
| f"Context details: {len(context.secrets) if context.secrets else 0} secrets available" | ||
| ) | ||
|
|
||
| # Log metadata if provided | ||
| if metadata: | ||
| await context.log.debug(f"Custom metadata: {metadata}") | ||
|
|
||
| return f"Logged user action: {user_action}" | ||
|
|
||
|
|
||
| @app.tool | ||
| async def batch_processing_logs( | ||
| context: Context, | ||
| items: Annotated[list[str], "Items to process"], | ||
| fail_on_item: Annotated[Optional[str], "Item that should fail"] = None, | ||
| ) -> Annotated[dict, "Processing results with detailed logs"]: | ||
| """Process items with detailed logging for each step.""" | ||
|
|
||
| results: dict[str, list] = {"successful": [], "failed": []} | ||
|
|
||
| await context.log.info(f"Starting batch processing of {len(items)} items") | ||
|
|
||
| for i, item in enumerate(items): | ||
| try: | ||
| # Log item start | ||
| await context.log.debug(f"Processing item {i + 1}/{len(items)}: {item}") | ||
|
|
||
| # Simulate failure if requested | ||
| if item == fail_on_item: | ||
| raise ValueError(f"Simulated failure for item: {item}") # noqa: TRY301 | ||
|
|
||
| # Simulate processing | ||
| await asyncio.sleep(0.1) | ||
|
|
||
| results["successful"].append(item) | ||
|
|
||
| except Exception as e: | ||
| await context.log.warning(f"Failed to process '{item}': {e!s}") | ||
| results["failed"].append({"item": item, "error": str(e)}) | ||
|
|
||
| # Log summary | ||
| await context.log.info( | ||
| f"Batch processing complete: {len(results['successful'])} successful, " | ||
| f"{len(results['failed'])} failed", | ||
| ) | ||
|
|
||
| return results | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| # Run the server | ||
| app.run(host="127.0.0.1", port=8000) | ||
| ``` | ||
|
|
||
| ### Run your MCP server | ||
|
|
||
| Set `log_level="DEBUG"` in `MCPApp` to see debug logs. | ||
|
|
||
| <Tabs | ||
| items={["HTTP transport (default)", "stdio transport (for Claude Desktop)"]} | ||
| storageKey="preferredTransport" | ||
| > | ||
| <Tabs.Tab> | ||
|
|
||
| ```bash | ||
| uv run logging.py http | ||
| ``` | ||
|
|
||
| For HTTP transport, view your server's API docs at [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs). | ||
|
|
||
| </Tabs.Tab> | ||
| <Tabs.Tab> | ||
|
|
||
| ```bash | ||
| uv run logging.py stdio | ||
| ``` | ||
|
|
||
| </Tabs.Tab> | ||
|
|
||
| </Tabs> | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Inconsistent Logging API Usage
The
demonstrate_log_levelsfunction usesawait context.log(level, log_message). This logging pattern is inconsistent with theawait context.log.<level>(message)API shown throughout the rest of the document, which likely causes a runtime error and could confuse users.