SSH MCP Server
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@SSH MCP ServerConnect to my production server at 192.168.1.100 with username admin"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
SSH MCP Server
Advanced SSH Session Manager for Model Context Protocol (MCP) with multi-session support and connection monitoring.
Features
Multi-Session Management: Create and manage multiple SSH connections simultaneously
Session Monitoring: Automatic connection health checks and timeout management
Command Execution: Execute commands on remote servers with timeout control
Session Persistence: Maintain long-running SSH sessions with metadata tracking
Automatic Cleanup: Intelligent session cleanup based on usage and timeouts
Related MCP server: Tmux MCP Server
Installation
Prerequisites
Python 3.11+
UV package manager
Claude Desktop
Setup with UV
Clone or download this project:
git clone <repository-url>
cd ssh_mcpInstall dependencies:
uv syncTest the installation:
uv run python main.pyClaude Desktop Configuration
1. Locate Claude Desktop Config File
Windows:
%APPDATA%\Claude\claude_desktop_config.jsonmacOS:
~/Library/Application Support/Claude/claude_desktop_config.jsonLinux:
~/.config/Claude/claude_desktop_config.json2. Add MCP Server Configuration
Add the following configuration to your claude_desktop_config.json:
{
"mcpServers": {
"ssh-session-manager": {
"command": "uv",
"args": [
"--directory",
"path/to/ssh_mcp",
"run",
"python",
"main.py"
],
"env": {
"PYTHONPATH": "path/to/ssh_mcp"
}
}
}
}Note: Replace path/to/ssh_mcp with the actual path to your project directory.
3. Restart Claude Desktop
After saving the configuration, restart Claude Desktop to load the MCP server.
Available Tools
ssh_connect
Create a new SSH connection session.
Parameters:
host(string): SSH server hostname or IP addressusername(string): SSH usernamepassword(string): SSH passwordport(int, optional): SSH port (default: 22)session_name(string, optional): Custom session name
Example:
Connect to my server using ssh_connect with host="192.168.1.100", username="admin", password="mypassword"ssh_execute
Execute a command in an existing SSH session.
Parameters:
session_id(string): ID of the SSH sessioncommand(string): Command to executetimeout(int, optional): Command timeout in seconds (default: 30)
Example:
Execute "ls -la" command in session "ssh_12345678"ssh_list_sessions
List all active SSH sessions.
Example:
Show me all active SSH sessionsssh_session_info
Get detailed information about a specific SSH session.
Parameters:
session_id(string): ID of the SSH session
Example:
Get information about session "ssh_12345678"ssh_close_session
Close a specific SSH session.
Parameters:
session_id(string): ID of the SSH session to close
Example:
Close SSH session "ssh_12345678"ssh_close_all_sessions
Close all active SSH sessions.
Example:
Close all SSH sessionsConfiguration Options
Session Manager Settings
You can modify the session manager settings in main.py:
ssh_manager = SSHSessionManager(
max_sessions=5, # Maximum number of concurrent sessions
session_timeout=600 # Session timeout in seconds (10 minutes)
)Security Considerations
Host Key Verification: Currently disabled for development. Enable proper host key verification for production use.
Password Storage: Passwords are not stored persistently but remain in memory during the session.
Network Security: Use this tool only on trusted networks.
Usage Examples
Basic SSH Connection
Connect to server 192.168.1.100 with username "admin" and password "mypass"Execute Multiple Commands
1. Connect to my server at example.com with username "user" and password "pass"
2. Execute "whoami" command
3. Execute "df -h" command
4. Show session informationSession Management
1. List all active sessions
2. Close session with oldest connection
3. Show remaining sessionsDependencies
asyncssh>=2.21.0: Asynchronous SSH client librarymcp[cli]>=1.9.2: Model Context Protocol frameworkparamiko>=3.5.1: SSH client library (backup/compatibility)
Development
Project Structure
ssh_mcp/
├── main.py # Main MCP server implementation
├── pyproject.toml # Project configuration and dependencies
├── uv.lock # Dependency lock file
├── README.md # This file
└── run_mcp.bat # Windows batch script for easy executionRunning in Development Mode
# Run the MCP server directly
uv run python main.py
# Or use the batch script (Windows)
run_mcp.batAdding New Features
Modify the
SSHSessionManagerclass inmain.pyAdd new MCP tools using the
@mcp.tool()decoratorUpdate this README with new tool documentation
Troubleshooting
Connection Issues
Verify SSH server is accessible and credentials are correct
Check firewall settings and network connectivity
Ensure SSH service is running on the target server
Claude Desktop Integration
Confirm UV is installed and accessible from system PATH
Verify the project path in the configuration is correct
Check Claude Desktop logs for error messages
Restart Claude Desktop after configuration changes
Session Timeouts
Increase
session_timeoutvalue in the session managerCheck network stability for long-running sessions
Monitor session activity with
ssh_list_sessions
License
This project is open source. Please refer to the license file for more information.
Contributing
Contributions are welcome! Please feel free to submit pull requests or open issues for bugs and feature requests.
Changelog
v0.1.0
Initial release
Multi-session SSH management
Basic command execution
Session monitoring and cleanup
Claude Desktop integration
Available Tools
6 toolsssh_close_all_sessionsB
모든 SSH 세션 종료
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It states the action (close all sessions) but doesn't describe what 'close' entails (e.g., graceful termination vs force kill), whether it requires specific permissions, if it's reversible, or what happens to active connections. For a potentially destructive operation with zero annotation coverage, this is inadequate.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, efficient phrase ('모든 SSH 세션 종료') that directly states the tool's purpose with zero wasted words. It's appropriately sized for a zero-parameter tool and front-loaded with the essential action.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool that performs a bulk operation on SSH sessions (potentially affecting multiple connections), the description is insufficient. With no annotations, no output schema, and no behavioral details, it lacks critical context about safety, permissions, effects, or return values. The agent cannot understand the full implications of using this tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, and schema description coverage is 100% (empty schema is fully described). The description doesn't need to explain parameters, so it meets the baseline expectation. No additional parameter semantics are required or provided.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description '모든 SSH 세션 종료' (Close all SSH sessions) clearly states the action (close/terminate) and target resource (all SSH sessions). It's specific enough to understand the tool's function, though it doesn't explicitly differentiate from the sibling 'ssh_close_session' which likely closes individual sessions.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides no guidance on when to use this tool versus alternatives like 'ssh_close_session' (for individual sessions) or 'ssh_list_sessions' (to view sessions first). There's no mention of prerequisites, warnings, or appropriate contexts for this bulk operation.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ssh_close_sessionC
특정 SSH 세션 종료
| Name | Required | Description | Default |
|---|---|---|---|
| session_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It states the action ('종료') but doesn't clarify whether this is destructive (e.g., terminates active processes), requires specific permissions, has side effects, or what happens on success/failure. For a mutation tool with zero annotation coverage, this leaves critical behavioral traits undocumented.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, efficient sentence in Korean that directly states the tool's purpose without unnecessary words. It's appropriately sized and front-loaded, with no wasted verbiage, making it easy to parse quickly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (a mutation operation with no annotations, no output schema, and 1 undocumented parameter), the description is insufficient. It doesn't cover behavioral aspects like effects, error conditions, or return values, leaving the agent with significant gaps in understanding how to use the tool effectively.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description doesn't add any parameter-specific information beyond what the input schema provides. With 0% schema description coverage and 1 parameter, the baseline is 3 since the schema already documents the parameter's existence and type, but the description fails to compensate by explaining what 'session_id' represents or where to obtain it.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action ('종료' meaning 'close' or 'terminate') and the resource ('SSH 세션' meaning 'SSH session'), making the purpose immediately understandable. However, it doesn't explicitly differentiate from sibling tools like 'ssh_close_all_sessions' or 'ssh_list_sessions' beyond the implied specificity of closing a single session.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides no guidance on when to use this tool versus alternatives. It doesn't mention prerequisites like needing an active session ID, nor does it contrast with 'ssh_close_all_sessions' for bulk operations or 'ssh_execute' for ongoing session use. Usage is implied but not explicitly stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ssh_connectC
SSH 서버에 연결하여 새 세션 생성
| Name | Required | Description | Default |
|---|---|---|---|
| host | Yes | ||
| password | Yes | ||
| port | No | ||
| session_name | No | ||
| username | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It states the tool creates a new SSH session, implying a network operation that may involve authentication and session management, but lacks details on critical behaviors such as error handling (e.g., connection failures), security implications (e.g., password transmission), session persistence, or rate limits. This is inadequate for a tool with potential side effects.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, efficient sentence that directly states the tool's purpose without unnecessary words. It's front-loaded with the core action, making it easy to parse, and every part contributes essential information, earning a top score for brevity and clarity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the complexity of SSH operations (involving network connectivity, authentication, and session management), no annotations, no output schema, and low parameter coverage, the description is incomplete. It fails to address key aspects like return values (e.g., session ID or status), error conditions, or behavioral nuances, making it insufficient for safe and effective use by an AI agent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate by explaining parameters, but it adds no semantic information beyond what the schema provides. The schema lists host, password, port, session_name, and username with basic types, but the description doesn't clarify their roles (e.g., host as IP/domain, password for authentication, port defaulting to 22, session_name for identification), leaving parameters largely unexplained.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action ('SSH 서버에 연결하여 새 세션 생성' translates to 'Connect to SSH server to create new session'), specifying the verb (connect), resource (SSH server), and outcome (new session). However, it doesn't explicitly differentiate from siblings like ssh_execute (which might execute commands) or ssh_list_sessions (which lists existing sessions), keeping it from a perfect score.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides no guidance on when to use this tool versus alternatives. It doesn't mention prerequisites (e.g., needing valid credentials), when not to use it (e.g., if a session already exists), or refer to sibling tools like ssh_execute for command execution or ssh_close_session for termination, leaving usage context vague.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ssh_executeC
SSH 세션에서 명령 실행
| Name | Required | Description | Default |
|---|---|---|---|
| command | Yes | ||
| session_id | Yes | ||
| timeout | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries full burden but offers minimal behavioral insight. It mentions execution but doesn't disclose critical traits like whether it's read-only/destructive, authentication needs, error handling, or output format (e.g., stdout/stderr). This is inadequate for a command execution tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, efficient sentence in Korean with no wasted words. It's appropriately sized and front-loaded, directly stating the tool's purpose without unnecessary elaboration.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (executing commands over SSH), lack of annotations, no output schema, and 0% schema coverage, the description is insufficient. It doesn't cover behavioral aspects, parameter meanings, or output expectations, leaving significant gaps for an AI agent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate but adds no parameter details. It doesn't explain what 'session_id' refers to (e.g., from ssh_connect), what 'command' entails, or 'timeout' implications. The description fails to provide meaningful context beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description 'SSH 세션에서 명령 실행' clearly states the action (execute command) and resource (SSH session) in Korean, which translates to 'Execute command in SSH session'. It's specific about what the tool does, though it doesn't explicitly differentiate from siblings like ssh_connect or ssh_session_info.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides no guidance on when to use this tool versus alternatives. It doesn't mention prerequisites (e.g., needing an active SSH session via ssh_connect first) or contrast with siblings like ssh_list_sessions. Usage is implied but not explicitly stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ssh_list_sessionsB
모든 활성 SSH 세션 목록 조회
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries full burden for behavioral disclosure. While '목록 조회' (list/retrieve) implies a read-only operation, it doesn't explicitly state whether this requires special permissions, what data format is returned, whether results are real-time or cached, or if there are rate limits. For a monitoring tool with zero annotation coverage, this is insufficient.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, efficient Korean sentence that immediately conveys the core functionality. Every word earns its place: '모든' (all) establishes scope, '활성' (active) provides important context, 'SSH 세션' (SSH sessions) identifies the resource, and '목록 조회' (list/retrieve) specifies the action.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given this is a monitoring tool with no annotations and no output schema, the description should do more to explain what information is returned (session IDs, user names, connection times, etc.) and any behavioral considerations. The current description is too minimal for an agent to understand what to expect from this tool's execution.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has 0 parameters with 100% schema description coverage, so the schema already fully documents the parameter situation. The description appropriately doesn't discuss parameters since none exist, earning a baseline 4 for not creating confusion about non-existent parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the verb ('목록 조회' - list/retrieve) and resource ('모든 활성 SSH 세션' - all active SSH sessions), making the purpose immediately understandable. It doesn't explicitly differentiate from siblings like ssh_session_info (which likely shows details of a specific session), but the 'all active' scope provides some implicit distinction.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage context through '모든 활성 SSH 세션' (all active SSH sessions), suggesting this is for monitoring current connections rather than historical data. However, it provides no explicit guidance on when to use this versus alternatives like ssh_session_info (for specific session details) or ssh_close_all_sessions (for termination).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ssh_session_infoC
특정 SSH 세션의 상세 정보 조회
| Name | Required | Description | Default |
|---|---|---|---|
| session_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It states the tool is for 'retrieving detailed information' (상세 정보 조회), implying a read-only operation, but doesn't specify what information is returned, whether it requires authentication, if there are rate limits, or how errors are handled. This is a significant gap for a tool with zero annotation coverage.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, efficient sentence in Korean that directly states the tool's purpose without unnecessary words. It is appropriately sized and front-loaded, with zero waste, making it easy for an agent to parse quickly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (a read operation with one parameter), lack of annotations, no output schema, and 0% schema description coverage, the description is incomplete. It doesn't explain return values, error conditions, or parameter details, leaving critical gaps for the agent to understand how to use the tool effectively.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema description coverage is 0%, so the description must compensate for the undocumented parameter 'session_id'. However, it adds no meaning beyond what the schema title ('Session Id') implies—it doesn't explain what a session ID is, how to obtain it, or its format (e.g., from 'ssh_list_sessions'). This fails to compensate for the low coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose as 'retrieving detailed information about a specific SSH session' (특정 SSH 세션의 상세 정보 조회), which is a specific verb+resource combination. However, it doesn't explicitly differentiate from sibling tools like 'ssh_list_sessions' (which likely lists multiple sessions) or 'ssh_execute' (which executes commands), so it misses full sibling differentiation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides no guidance on when to use this tool versus alternatives. It doesn't mention prerequisites (e.g., needing an active session), exclusions, or comparisons to siblings like 'ssh_list_sessions' for broader queries or 'ssh_execute' for command execution, leaving the agent with no usage context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
6 tool updates
v1.0.0- First observed
ssh_close_all_sessions - First observed
ssh_close_session - First observed
ssh_connect - First observed
ssh_execute - First observed
ssh_list_sessions - First observed
ssh_session_info
TDQS
Each tool has a clearly distinct purpose with no ambiguity: connecting, listing sessions, getting session info, executing commands, closing a specific session, and closing all sessions. The descriptions clearly differentiate between operations on sessions versus commands, and between individual and bulk actions.
All tools follow a consistent 'ssh_verb_noun' pattern with snake_case, using clear action words like connect, list, execute, close, and info. The naming is predictable and readable throughout the set.
Six tools is well-scoped for an SSH server, covering the core lifecycle of session management (connect, list, info, execute, close individual, close all). Each tool earns its place without redundancy or obvious gaps.
The toolset provides complete CRUD/lifecycle coverage for SSH sessions: creation (connect), reading (list_sessions, session_info), execution (execute), and deletion (close_session, close_all_sessions). There are no dead ends or missing operations for the domain.
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Scoped, audited SSH exec, sessions, and SFTP on your saved servers without exposing credentials
Persistent context for Claude. Your AI always knows your projects and next actions across sessions.
Run commands and read/write files on your servers over Termalin's keyless tunnels (hosted MCP).
- sentinelOAuthio.rootstuff
Uptime, SSL, DNS and domain monitoring you can talk to from Claude or any MCP client.
Related MCP Servers
- FlicenseBqualityFmaintenanceProvides sophisticated context management for Claude, enabling persistent context across sessions, project-specific organization, and conversation continuity.415-
- AlicenseAqualityFmaintenanceEnables Claude Desktop to interact with and view tmux session content, allowing AI assistants to read from, control, and observe terminal sessions.13256299MIT
- AlicenseAqualityDmaintenanceA server that lets Claude desktop app execute terminal commands on your computer and edit files through Model Context Protocol, featuring command execution, process management, and advanced file operations.1938,9236MIT
- FlicenseNot gradedqualityDmaintenanceProvides system monitoring and management capabilities for Claude CLI, allowing users to view system information, track resource usage, and manage processes through natural language commands.-
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/balloonf/ssh_mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server