feat: Admin menu + API key management UI

This commit is contained in:
2026-05-08 03:17:28 +00:00
parent 610e48253b
commit b8e0c3f998
+147
View File
@@ -0,0 +1,147 @@
<?php
namespace AskTamMCP\Core;
defined('ABSPATH') || exit;
/**
* WP Admin menu + settings page for AskTam MCP.
*/
class AdminMenu {
public function __construct() {
add_action('admin_menu', [$this, 'register']);
add_action('admin_enqueue_scripts', [$this, 'enqueueAssets']);
}
public function register(): void {
add_menu_page(
'AskTam MCP',
'AskTam MCP',
'manage_options',
'asktam-mcp',
[$this, 'renderDashboard'],
'dashicons-rest-api',
80
);
add_submenu_page('asktam-mcp', 'API Keys', 'API Keys', 'manage_options', 'asktam-mcp', [$this, 'renderDashboard']);
add_submenu_page('asktam-mcp', 'Settings', 'Settings', 'manage_options', 'asktam-mcp-settings', [$this, 'renderSettings']);
}
public function enqueueAssets(string $hook): void {
if (!in_array($hook, ['toplevel_page_asktam-mcp', 'asktam-mcp_page_asktam-mcp-settings'], true)) {
return;
}
wp_enqueue_style('asktam-mcp-admin', ASKTAM_MCP_URL . 'assets/admin.css', [], ASKTAM_MCP_VERSION);
}
public function renderDashboard(): void {
global $wpdb;
$table = $wpdb->prefix . 'asktam_mcp_keys';
$keys = $wpdb->get_results("SELECT * FROM {$table} ORDER BY created_at DESC");
$sseUrl = rest_url('asktam-mcp/v1/sse');
$infoUrl = rest_url('asktam-mcp/v1/info');
?>
<div class="wrap">
<h1>AskTam MCP <span style="font-size:13px;font-weight:normal;color:#666;">v<?php echo esc_html(ASKTAM_MCP_VERSION); ?></span></h1>
<div class="notice notice-info" style="padding:12px 16px;margin:12px 0;">
<strong>MCP Endpoint:</strong>
<code style="background:#f0f0f0;padding:3px 8px;border-radius:3px;"><?php echo esc_html($sseUrl); ?></code>
&nbsp;
<a href="<?php echo esc_url($infoUrl); ?>" target="_blank">Info →</a>
</div>
<h2 style="margin-top:24px;">API Keys</h2>
<p>Add the <code>X-MCP-API-Key</code> header to your MCP client with one of the keys below.</p>
<form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
<?php wp_nonce_field('asktam_mcp_create_key', '_wpnonce_mcp'); ?>
<input type="hidden" name="action" value="asktam_mcp_create_key">
<table class="form-table" style="max-width:600px;">
<tr>
<th>Name</th>
<td><input type="text" name="key_name" class="regular-text" placeholder="e.g. Claude Desktop" required></td>
</tr>
<tr>
<th>Scopes</th>
<td>
<label><input type="checkbox" name="scopes[]" value="read" checked> Read</label> &nbsp;
<label><input type="checkbox" name="scopes[]" value="write"> Write</label> &nbsp;
<label><input type="checkbox" name="scopes[]" value="admin"> Admin</label> &nbsp;
<label><input type="checkbox" name="scopes[]" value="woocommerce"> WooCommerce</label>
</td>
</tr>
</table>
<?php submit_button('Generate API Key', 'primary', 'submit', false); ?>
</form>
<?php if ($keys): ?>
<table class="wp-list-table widefat fixed striped" style="max-width:900px;margin-top:24px;">
<thead>
<tr>
<th>Name</th>
<th>API Key</th>
<th>Scopes</th>
<th>Last Used</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($keys as $key): ?>
<tr>
<td><?php echo esc_html($key->name); ?></td>
<td><code style="font-size:11px;"><?php echo esc_html(substr($key->api_key, 0, 12) . '...'); ?></code>
<button onclick="navigator.clipboard.writeText('<?php echo esc_js($key->api_key); ?>')" class="button button-small">Copy</button>
</td>
<td><?php echo esc_html($key->scopes); ?></td>
<td><?php echo $key->last_used ? esc_html($key->last_used) : '—'; ?></td>
<td><?php echo $key->is_active ? '<span style="color:green">Active</span>' : '<span style="color:red">Inactive</span>'; ?></td>
<td>
<form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>" style="display:inline;">
<?php wp_nonce_field('asktam_mcp_revoke_' . $key->id, '_wpnonce_mcp'); ?>
<input type="hidden" name="action" value="asktam_mcp_revoke_key">
<input type="hidden" name="key_id" value="<?php echo (int) $key->id; ?>">
<button type="submit" class="button button-small" onclick="return confirm('Revoke this key?')">Revoke</button>
</form>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</div>
<?php
}
public function renderSettings(): void {
$settings = get_option('asktam_mcp_settings', []);
?>
<div class="wrap">
<h1>AskTam MCP Settings</h1>
<form method="post" action="options.php">
<?php settings_fields('asktam_mcp_settings_group'); ?>
<table class="form-table" style="max-width:600px;">
<tr>
<th>Rate Limit (req/min)</th>
<td><input type="number" name="asktam_mcp_settings[rate_limit]" value="<?php echo (int) ($settings['rate_limit'] ?? 60); ?>" min="1" max="300"></td>
</tr>
<tr>
<th>Log Requests</th>
<td><input type="checkbox" name="asktam_mcp_settings[log_requests]" value="1" <?php checked($settings['log_requests'] ?? true); ?>></td>
</tr>
<tr>
<th>Allow Raw SQL</th>
<td><input type="checkbox" name="asktam_mcp_settings[allow_raw_sql]" value="1" <?php checked($settings['allow_raw_sql'] ?? false); ?>>
<p class="description">Allows admin-scoped keys to run SELECT queries directly.</p>
</td>
</tr>
</table>
<?php submit_button(); ?>
</form>
</div>
<?php
}
}