A collection of optimized MCP services for AI Agents
Project description
openmcp ๐
The Ultimate MCP Server for AI Agents
Supercharge your AI coding assistants with powerful web automation
๐ฏ What is openmcp?
openmcp is a production-ready MCP (Model Context Protocol) server that gives AI agents superpowers for web automation. Whether you're using Cursor, Claude, ChatGPT, or any other AI assistant, openmcp provides secure, scalable access to browser automation capabilities.
๐ Perfect for AI-Powered Development
- ๐ฅ Cursor Integration - Let Cursor automate web testing and scraping
- ๐ค Claude Desktop - Give Claude the ability to browse and interact with websites
- ๐ป VS Code Extensions - Power up your AI coding assistants
- ๐ง Custom AI Agents - Build agents that can navigate the web
- ๐ Data Collection - Automate web scraping and form filling
- ๐งช Testing Automation - Let AI write and run web tests
โจ Key Features
๐ Enterprise Ready
|
๐ Universal Access
|
๐ง Powerful Automation
|
๐ Developer Friendly
|
๐ Quick Start (5 Minutes)
1. Install openmcp
# Clone and install
git clone https://github.com/openmcp-pro/openmcp.git
cd openmcp
pip install -e .
2. Initialize and Start
# Create configuration and get your API key
openmcp init-config
# Start the server (FastMCP with streamable-http transport)
openmcp serve
๐ That's it! Your OpenMCP FastMCP server is running on http://localhost:8000
๐ก Transport Options
Choose your transport protocol:
# Default: Official MCP with streamable-http transport (recommended)
openmcp serve
# Official MCP with SSE transport (real-time streaming)
openmcp serve --transport sse
# Legacy REST API (for custom integrations)
openmcp serve --transport rest --port 9000
3. Use the Super Simple Interface
import asyncio
import openmcp
async def main():
# Super simple - just one line!
mcp = openmcp.MCP("browseruse")
# Create a browser session
session = await mcp.create_session()
# Navigate and take screenshot
await session.navigate("https://example.com")
await session.screenshot("example.png")
# Clean up
await session.close()
# Or even simpler with context manager:
async def even_simpler():
async with openmcp.browser() as browser:
await browser.navigate("https://example.com")
await browser.click("#some-button")
await browser.screenshot("result.png")
# One-liner screenshot
async def one_liner():
await openmcp.screenshot("https://example.com", "quick.png")
asyncio.run(main())
๐ Authentication & Development Mode
openmcp supports multiple authentication modes to make development easy while keeping production secure:
๐ Development Mode (Localhost)
No API key required when connecting from localhost! Perfect for development:
# From localhost - no auth needed!
import httpx
async def localhost_example():
# Direct API calls without authentication
async with httpx.AsyncClient() as client:
response = await client.get("http://localhost:9000/api/v1/services")
print(response.json())
# Or with the simple interface
import openmcp
mcp = openmcp.MCP("browseruse") # No API key needed from localhost!
๐งช Mock API Key for Testing
Use the built-in mock API key openmcp-localhost-auth for testing from any location:
# Works from anywhere - great for CI/CD
import openmcp
# Using mock API key
mcp = openmcp.MCP("browseruse", api_key="openmcp-localhost-auth")
# Or direct HTTP with mock key
headers = {"Authorization": "Bearer openmcp-localhost-auth"}
๐ Production API Keys
For production use, generate secure API keys:
# Generate production API key
openmcp init-config # Shows your API key
# Use in production
export OPENMCP_API_KEY="bmcp_your-production-key-here"
๐ ๏ธ Configuration Options
Control authentication behavior in your config:
# config.yaml
auth:
allow_localhost: true # Enable localhost bypass (default: true)
mock_api_key: "openmcp-localhost-auth" # Mock key for testing
secret_key: "your-secret-key" # JWT secret
๐ฏ Which Mode to Use?
- ๐ Local Development: No API key needed - just run and go!
- ๐งช Testing/CI: Use
openmcp-localhost-authmock key - ๐ Production: Generate and use secure
bmcp_API keys - ๐ Restricted: Disable localhost mode in production configs
โก Super Simple Interface
NEW! openmcp now has an incredibly simple Python interface:
import openmcp
# Just one line to get started!
mcp = openmcp.MCP("browseruse")
๐ฏ Three Ways to Use openmcp
1. Session-based (Full Control)
mcp = openmcp.MCP("browseruse")
session = await mcp.create_session()
await session.navigate("https://example.com")
await session.click("#button")
await session.screenshot("result.png")
await session.close()
2. Context Manager (Recommended)
async with openmcp.browser() as browser:
await browser.navigate("https://example.com")
await browser.type("#search", "openmcp")
await browser.click("#submit")
await browser.screenshot("search_results.png")
# Automatically cleaned up!
3. One-Liners (Super Quick)
# Quick screenshot
await openmcp.screenshot("https://example.com", "page.png")
# Quick form test
await openmcp.test_form("https://example.com/contact", {
"#name": "John Doe",
"#email": "john@example.com"
})
๐ค Perfect for AI Assistants
Ask Cursor or Claude:
- "Create a script using openmcp.browser() to test our login form"
- "Use openmcp to take screenshots of all our product pages"
- "Write a openmcp script that fills out contact forms automatically"
They'll generate clean, simple code using the new interface!
๐ฅ Using openmcp with Cursor
Method 1: Super Simple Interface (Recommended)
Just add this to your project and ask Cursor to use it:
import openmcp
# Cursor will generate code like this:
async def test_website():
async with openmcp.browser() as browser:
await browser.navigate("https://yoursite.com")
await browser.click("#login-button")
await browser.type("#email", "test@example.com")
await browser.screenshot("login_page.png")
Method 2: Direct HTTP Integration
Add this to your Cursor project to give your AI assistant web automation powers:
# cursor_openmcp.py - Add this to your project
import httpx
import asyncio
from typing import Dict, Any, Optional
class CursorWebAutomation:
"""Web automation helper for Cursor AI assistant."""
def __init__(self, api_key: str = "", base_url: str = "http://localhost:9000"):
self.api_key = api_key
self.base_url = base_url
# Only add auth header if API key is provided (localhost mode doesn't need it)
self.headers = {"Authorization": f"Bearer {api_key}"} if api_key else {}
self.session_id: Optional[str] = None
async def start_browser(self, headless: bool = True) -> str:
"""Start a browser session for automation."""
async with httpx.AsyncClient() as client:
response = await client.post(
f"{self.base_url}/api/v1/services/browseruse/call",
headers=self.headers,
json={
"tool_name": "create_session",
"arguments": {"headless": headless, "timeout": 30}
}
)
result = response.json()
if result["success"]:
self.session_id = result["result"]["session_id"]
return self.session_id
raise Exception(f"Failed to start browser: {result}")
async def navigate(self, url: str) -> Dict[str, Any]:
"""Navigate to a URL."""
if not self.session_id:
await self.start_browser()
async with httpx.AsyncClient() as client:
response = await client.post(
f"{self.base_url}/api/v1/services/browseruse/call",
headers=self.headers,
json={
"tool_name": "navigate",
"arguments": {"url": url},
"session_id": self.session_id
}
)
return response.json()
async def find_and_click(self, selector: str) -> Dict[str, Any]:
"""Find and click an element."""
async with httpx.AsyncClient() as client:
response = await client.post(
f"{self.base_url}/api/v1/services/browseruse/call",
headers=self.headers,
json={
"tool_name": "click_element",
"arguments": {"selector": selector},
"session_id": self.session_id
}
)
return response.json()
async def type_text(self, selector: str, text: str) -> Dict[str, Any]:
"""Type text into an input field."""
async with httpx.AsyncClient() as client:
response = await client.post(
f"{self.base_url}/api/v1/services/browseruse/call",
headers=self.headers,
json={
"tool_name": "type_text",
"arguments": {"selector": selector, "text": text},
"session_id": self.session_id
}
)
return response.json()
async def screenshot(self, save_path: str = "screenshot.png") -> str:
"""Take a screenshot and save it."""
async with httpx.AsyncClient() as client:
response = await client.post(
f"{self.base_url}/api/v1/services/browseruse/call",
headers=self.headers,
json={
"tool_name": "take_screenshot",
"arguments": {},
"session_id": self.session_id
}
)
result = response.json()
if result["success"]:
import base64
screenshot_data = base64.b64decode(result["result"]["screenshot"])
with open(save_path, "wb") as f:
f.write(screenshot_data)
return save_path
raise Exception("Screenshot failed")
# Usage example for Cursor
async def demo_for_cursor():
"""Demo function that Cursor can call."""
# No API key needed from localhost! For remote use: api_key="openmcp-localhost-auth"
automation = CursorWebAutomation() # Empty for localhost, or use mock key
# Navigate to a website
await automation.navigate("https://example.com")
# Take a screenshot
screenshot_path = await automation.screenshot("example_page.png")
print(f"Screenshot saved: {screenshot_path}")
# You can now ask Cursor to:
# - Automate form filling
# - Scrape website data
# - Test web applications
# - Generate web automation scripts
# Run this in Cursor's terminal
if __name__ == "__main__":
asyncio.run(demo_for_cursor())
Method 2: Official MCP Integration (Recommended)
For native MCP support in Cursor, add this configuration:
// .cursor/mcp_config.json
{
"mcpServers": {
"openmcp": {
"command": "openmcp",
"args": ["serve", "--transport", "sse"],
"env": {}
}
}
}
Note: Uses the new FastMCP SSE transport for real-time streaming support.
๐ฏ Cursor Use Cases
Ask Cursor to:
- "Create a script that logs into this website and downloads all PDFs"
- "Write a test that fills out this contact form and verifies submission"
- "Build a scraper that extracts product prices from this e-commerce site"
- "Automate taking screenshots of our website on different screen sizes"
๐ค Using openmcp with Claude Desktop
Setup Claude Desktop Integration
- Install Claude Desktop from Anthropic
- Configure MCP Server in Claude's settings:
// Claude Desktop MCP Configuration
{
"mcpServers": {
"openmcp-browser": {
"command": "openmcp",
"args": ["serve", "--transport", "sse"]
}
}
}
Note: Uses FastMCP with SSE transport for optimal Claude Desktop integration.
- Restart Claude Desktop - openmcp tools will appear automatically
๐ฏ Claude Desktop Use Cases
Ask Claude:
- "Please navigate to GitHub and take a screenshot of the trending repositories"
- "Fill out this job application form with my resume details"
- "Check if my website loads correctly and take screenshots"
- "Find all the contact forms on this website and test them"
Example Claude Conversation
You: "Please help me test the contact form on https://example.com"
Claude: I'll help you test the contact form. Let me:
1. Create a browser session
2. Navigate to the website
3. Find the contact form
4. Fill it out with test data
5. Take screenshots of the process
[Claude automatically uses openmcp tools to complete the task]
๐ Transport Protocols
OpenMCP supports three transport protocols to meet different integration needs:
๐ฏ Streamable-HTTP (Default & Recommended)
# Start with streamable-http transport
openmcp serve
# or explicitly:
openmcp serve --transport streamable-http
โ Best for:
- Official MCP clients (Cursor, Claude Desktop, custom clients)
- Production deployments - Reliable HTTP-based communication
- Load balancers - Standard HTTP protocol
- Firewall-friendly - Uses standard HTTP ports
๐ Connect with:
from mcp.client.streamable_http import streamablehttp_client
from mcp.client.session import ClientSession
async with streamablehttp_client('http://localhost:8000/') as (read_stream, write_stream, session_id):
session = ClientSession(read_stream, write_stream)
async with session:
await session.initialize()
tools = await session.list_tools()
โก Server-Sent Events (SSE)
# Start with SSE transport
openmcp serve --transport sse
โ Best for:
- Real-time applications - Live progress updates
- Streaming operations - Long-running tasks with progress
- Web dashboards - Browser-based monitoring
- Development & debugging - Live operation visibility
๐ Connect with:
from mcp.client.sse import sse_client
from mcp.client.session import ClientSession
async with sse_client('http://localhost:8000/sse') as (read_stream, write_stream):
session = ClientSession(read_stream, write_stream)
async with session:
await session.initialize()
tools = await session.list_tools()
๐ง REST API (Legacy)
# Start with REST transport
openmcp serve --transport rest --port 9000
โ Best for:
- Custom integrations - Direct HTTP API access
- Any programming language - Standard REST endpoints
- Existing applications - Drop-in replacement for web automation
- Quick prototyping - Simple curl commands
๐ Connect with:
import httpx
# Direct REST API calls
async with httpx.AsyncClient() as client:
response = await client.get("http://localhost:9000/api/v1/services")
services = response.json()
# Create browser session
response = await client.post(
"http://localhost:9000/api/v1/services/browseruse/call",
json={"tool_name": "create_session", "arguments": {"headless": True}}
)
๐๏ธ Transport Comparison
| Feature | Streamable-HTTP | SSE | REST API |
|---|---|---|---|
| MCP Protocol | โ Official | โ Official | โ Custom |
| Official Clients | โ Full support | โ Full support | โ Not supported |
| Real-time Updates | โ Request/Response | โ Live streaming | โ Request/Response |
| HTTP Compatibility | โ Standard HTTP | โ Standard HTTP | โ Standard HTTP |
| Custom Integrations | โ ๏ธ MCP required | โ ๏ธ MCP required | โ Any language |
| Production Ready | โ Recommended | โ Good | โ Legacy support |
๐ก Choosing the Right Transport
- ๐ฏ Starting fresh? Use streamable-http (default)
- โก Need real-time? Use SSE transport
- ๐ง Custom integration? Use REST API transport
- ๐ค Official MCP clients? Use streamable-http or SSE
๐ง Available Tools
| Tool | Description | Example Use Case |
|---|---|---|
| create_session | Start new browser | "Start a browser for testing" |
| navigate | Go to URL | "Open the login page" |
| find_elements | Locate page elements | "Find all the buttons on this page" |
| click_element | Click buttons/links | "Click the submit button" |
| type_text | Fill input fields | "Enter my email address" |
| take_screenshot | Capture page image | "Take a screenshot for documentation" |
| close_session | End browser session | "Clean up when done" |
๐ Real-World Examples
Example 1: Automated Testing with Cursor
# test_automation.py - Generated by Cursor with openmcp
import asyncio
from cursor_openmcp import CursorWebAutomation
async def test_login_flow():
"""Test user login functionality."""
automation = CursorWebAutomation() # No auth needed from localhost!
# Navigate to login page
await automation.navigate("https://yourapp.com/login")
# Fill login form
await automation.type_text("#email", "test@example.com")
await automation.type_text("#password", "testpass123")
# Submit form
await automation.find_and_click("#login-button")
# Verify success
await asyncio.sleep(2) # Wait for redirect
screenshot = await automation.screenshot("login_success.png")
print(f"Login test completed. Screenshot: {screenshot}")
# Cursor can generate and run this automatically!
asyncio.run(test_login_flow())
Example 2: Data Collection with Claude
You: "Please collect all product names and prices from https://shop.example.com"
Claude: I'll help you scrape the product data. Let me:
1. Navigate to the shop website
2. Find all product elements
3. Extract names and prices
4. Save the data to a CSV file
[Uses openmcp tools automatically]
Here's the collected data:
- Product A: $29.99
- Product B: $39.99
- Product C: $19.99
Data saved to products.csv
Example 3: Form Automation
# Generated by AI assistant using openmcp
async def automate_job_application():
automation = CursorWebAutomation() # Localhost = no auth required!
# Navigate to job application
await automation.navigate("https://company.com/careers/apply")
# Fill personal information
await automation.type_text("#first-name", "John")
await automation.type_text("#last-name", "Doe")
await automation.type_text("#email", "john@example.com")
# Upload resume (if file upload is supported)
await automation.find_and_click("#resume-upload")
# Take screenshot for verification
await automation.screenshot("application_filled.png")
print("Job application automated successfully!")
๐ Advanced Configuration
Custom Service Configuration
# config.yaml
server:
host: "0.0.0.0"
port: 9000
debug: false
auth:
secret_key: "your-secret-key"
services:
- name: "browseruse"
enabled: true
config:
headless: true
timeout: 30
max_sessions: 10 # Allow more concurrent sessions
# Add more services here
- name: "future_service"
enabled: false
Environment Variables
# .env
OPENMCP_SECRET_KEY=your-production-secret
OPENMCP_HOST=0.0.0.0
OPENMCP_PORT=9000
OPENMCP_MAX_SESSIONS=20
๐ณ Production Deployment
Docker Deployment
# Build and run
docker build -t openmcp .
docker run -p 9000:9000 -e OPENMCP_SECRET_KEY=your-secret openmcp
Docker Compose
# docker-compose.yml
version: '3.8'
services:
openmcp:
build: .
ports:
- "9000:9000"
environment:
- OPENMCP_SECRET_KEY=${SECRET_KEY}
volumes:
- ./config.yaml:/app/config.yaml
restart: unless-stopped
Cloud Deployment
Deploy to any cloud platform:
- AWS ECS/Fargate - Container-ready
- Google Cloud Run - Serverless scaling
- Azure Container Instances - Easy deployment
- DigitalOcean Apps - Simple setup
- Railway/Render - One-click deploy
๐ Security Best Practices
API Key Management
# Generate secure API keys
openmcp create-key "production-agent" --expires 365
# Rotate keys regularly
openmcp create-key "new-key" --expires 90
# Update your applications
# Revoke old key
Network Security
# config.yaml - Production settings
server:
host: "127.0.0.1" # Only local access
port: 9000
auth:
allow_localhost: false # Disable localhost bypass in production
mock_api_key: "" # Disable mock key in production
# Use reverse proxy (nginx/traefik) for HTTPS
# Enable firewall rules
# Use VPN for remote access
๐ Monitoring & Observability
Health Checks
# Monitor server health
curl http://localhost:9000/health
# Check service status
curl -H "Authorization: Bearer $API_KEY" \
http://localhost:9000/api/v1/services/browseruse/status
Logging
# Structured logging is built-in
import structlog
logger = structlog.get_logger()
# All API calls are automatically logged
# Browser actions are tracked
# Errors are captured with context
๐ช Git Hooks
This repository includes git hooks to maintain clean commit history:
Claude Keyword Filter
Automatically removes lines containing "Claude" from commit messages to keep them professional:
# Input commit message:
"Add new feature
Claude helped with implementation
Fix authentication bug"
# Automatically filtered to:
"Add new feature
Fix authentication bug"
Features:
- ๐ Auto-Detection - Finds "Claude" keyword (case-insensitive)
- ๐งน Smart Filtering - Removes only problematic lines
- ๐ Safe Fallback - Never leaves empty commit messages
- ๐ Visual Feedback - Shows what was filtered
See GIT_HOOKS.md for complete documentation.
๐ก Server-Sent Events (SSE) Streaming
OpenMCP supports real-time streaming of long-running operations using Server-Sent Events:
๐ Real-Time Browser Automation
Stream browser operations with live progress updates:
import asyncio
import httpx
import json
async def stream_browser_session():
async with httpx.AsyncClient() as client:
async with client.stream(
"POST",
"http://localhost:9000/api/v1/services/browseruse/stream",
json={
"tool_name": "create_session",
"arguments": {"headless": True}
}
) as response:
async for line in response.aiter_lines():
if line.startswith("data: "):
event = json.loads(line[6:])
print(f"{event['type']}: {event['message']}")
if event['type'] == 'progress':
print(f"Progress: {event.get('progress', 0)}%")
asyncio.run(stream_browser_session())
๐ SSE Event Types
start- Operation beginsprogress- Progress updates with percentagesuccess- Operation completed successfullyerror- Operation failedcomplete- Final completion event
๐ Web Dashboard
Open examples/sse_web_demo.html in your browser for a live web interface:
- โ Real-time progress bars
- โ Live operation logs
- โ Interactive controls
- โ No API key needed (localhost)
โก Quick SSE Examples
# Python streaming examples
python examples/simple_sse_demo.py
python examples/sse_streaming_example.py
# Web interface
open examples/sse_web_demo.html
๐ง SSE Endpoints
All MCP services support streaming via /stream endpoints:
POST /api/v1/services/{service_name}/stream
Content-Type: application/json
{
"tool_name": "navigate",
"arguments": {"url": "https://example.com"},
"session_id": "session-id-here"
}
Perfect for:
- Long-running operations (web crawling, form automation)
- Real-time dashboards (monitoring browser sessions)
- Progress tracking (screenshot capture, navigation)
- Live debugging (step-by-step operation visibility)
๐ค Contributing & Extending
Adding New Services
# my_custom_service.py
from openmcp.services.base import BaseMCPService
class MyCustomService(BaseMCPService):
def get_tools(self):
return [{
"name": "my_tool",
"description": "My custom automation tool",
"parameters": {
"type": "object",
"properties": {
"input": {"type": "string"}
}
}
}]
async def call_tool(self, tool_name, arguments, session_id=None):
if tool_name == "my_tool":
# Implement your custom logic
return {"result": f"Processed: {arguments['input']}"}
Community Extensions
Planned Services:
- ๐ง Email Automation - Send/read emails
- ๐ฑ Mobile Testing - Appium integration
- ๐๏ธ Database Operations - SQL query execution
- ๐ API Testing - REST/GraphQL testing
- ๐ SEO Analysis - Website optimization
๐ Troubleshooting
Common Issues
Server won't start?
# Check port availability
netstat -an | grep 9000
# Try different port
openmcp serve --port 8001
Browser automation fails?
# Install Chrome/Chromium
# Ubuntu/Debian:
sudo apt-get install chromium-browser
# macOS:
brew install --cask google-chrome
# Windows: Download from Google
API authentication errors?
# From localhost? No auth needed!
curl http://localhost:9000/api/v1/services
# Use mock key for testing
curl -H "Authorization: Bearer openmcp-localhost-auth" \
http://localhost:9000/api/v1/services
# Regenerate API key for production
openmcp init-config --force
# Check key format (should start with 'bmcp_')
echo $API_KEY
Cursor/Claude not connecting?
# Verify MCP server starts with correct transport
openmcp serve --transport sse
# Check MCP configuration syntax in your client
# Restart Cursor/Claude Desktop after configuration changes
# Test official MCP client connection
python -c "
from mcp.client.sse import sse_client
import asyncio
async def test():
async with sse_client('http://localhost:8000/sse') as streams:
print('โ
MCP connection successful')
asyncio.run(test())
"
๐ Documentation & Resources
- ๐ REST API Documentation - Interactive OpenAPI docs (when using
--transport rest) - ๐ฏ MCP Protocol Reference - Official MCP specification
- ๐ฏ MCP Examples Guide - Comprehensive usage examples
- โก Quick Start Guide - 5-minute setup
- ๐ง Configuration Reference - All settings explained
- ๐ Troubleshooting Guide - Common issues & solutions
๐ Community & Support
- ๐ Official Website - Documentation and resources
- ๐ฌ GitHub Discussions - Community Q&A
- ๐ Issue Tracker - Bug reports & features
- ๐ง Email Support - Direct help
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.
๐ Acknowledgments
Built with love using:
- FastAPI - Modern Python web framework
- Selenium - Web browser automation
- Pydantic - Data validation
- Typer - CLI interface
- Structlog - Structured logging
๐ Ready to supercharge your AI agents with web automation?
Get Started Now โข View Examples โข Join Community โข Documentation
Made with โค๏ธ for the AI development community
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file openmcp-0.6.0.tar.gz.
File metadata
- Download URL: openmcp-0.6.0.tar.gz
- Upload date:
- Size: 57.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6f748c909e3dde85c10f2c101c1137e434416f1c75d442cbb9ada91e87175e23
|
|
| MD5 |
3325be9050def9be3a62822447ee9c48
|
|
| BLAKE2b-256 |
1800ae05b00525118df3d2ee5d8f01fd6dfe2661cba92110efbd0332bfdc718b
|
File details
Details for the file openmcp-0.6.0-py3-none-any.whl.
File metadata
- Download URL: openmcp-0.6.0-py3-none-any.whl
- Upload date:
- Size: 44.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2e8f4a61ca7165637c77c4a97b2490b0d9a275a10fcbda6fe1d332ee725b5391
|
|
| MD5 |
32f34f3f792ece0e4ef127fa97802ced
|
|
| BLAKE2b-256 |
72960543fc6da139550b44bb259d48a0c62f5420b82ca4e07d8ebe72a5dbc384
|