# Activity Log for MCP

Monitor and log MCP (Model Context Protocol) requests on your WordPress site.

Activity Log for MCP captures every MCP request made to your WordPress REST API, records the full request/response cycle, and provides both a visual admin interface and a programmatic API for querying logs. It also exposes MCP abilities so AI agents can query their own activity history.

> Not affiliated with Anthropic or the Model Context Protocol project. "MCP" is referenced solely to describe the open protocol that this plugin observes.

## Requirements

- WordPress 6.9+
- PHP 7.4+

## Installation

1. Upload the `activity-log-for-mcp` folder to `/wp-content/plugins/`
2. Activate through the Plugins menu
3. Navigate to **Tools > Activity Log for MCP** in the admin sidebar

## How It Works

The plugin hooks into `rest_pre_dispatch` and `rest_post_dispatch` to capture MCP requests. A request is identified as MCP if it contains the `Mcp-Session-Id` header. For each matching request, the plugin logs:

- Route, method, and server namespace
- Request headers and body
- Response status and body
- Tool name (extracted from JSON-RPC params)
- Tool execution status (success/error/unknown)
- User ID and timestamp

All data is stored in a custom table (`{prefix}alfmcp_requests`).

## Admin Interface

Built with React and `@wordpress/components`. Features:

- **Filterable log list** with date range, ability, and user filters
- **Sortable columns** for date, user, and API endpoint
- **Per-page selector** (10, 20, 50, 100, 500) with persistent preference
- **Detail modal** with collapsible request/response panels and copy buttons
- **Three-dot menu** for CSV export and clearing logs
- **Clickable ability names** to open the detail view

## REST API

All endpoints require authentication and `manage_options` capability.

### Endpoints

| Method | Endpoint | Description |
|--------|----------|-------------|
| `GET` | `/wp-json/activity-log-for-mcp/v1/requests` | List logs (paginated, filtered, sorted) |
| `GET` | `/wp-json/activity-log-for-mcp/v1/stats` | Aggregate statistics |
| `GET` | `/wp-json/activity-log-for-mcp/v1/sessions/{id}` | Logs for a specific MCP session |
| `GET` | `/wp-json/activity-log-for-mcp/v1/search` | Full-text search |
| `GET` | `/wp-json/activity-log-for-mcp/v1/errors` | Recent errors |
| `GET` | `/wp-json/activity-log-for-mcp/v1/tool-performance` | Per-tool metrics |
| `GET` | `/wp-json/activity-log-for-mcp/v1/filters` | Available filter values |
| `GET` | `/wp-json/activity-log-for-mcp/v1/export-csv` | Download CSV |
| `DELETE` | `/wp-json/activity-log-for-mcp/v1/requests` | Clear all logs |
| `DELETE` | `/wp-json/activity-log-for-mcp/v1/retention` | Delete logs before a date |

### Parameters

**GET /requests**

| Param | Type | Default | Description |
|-------|------|---------|-------------|
| `page` | integer | 1 | Page number |
| `per_page` | integer | 20 | Results per page (1-500) |
| `date_from` | string | | Start date (Y-m-d) or datetime (Y-m-d H:i:s) |
| `date_to` | string | | End date or datetime |
| `tool` | string | | Filter by tool name |
| `user_id` | string | | Filter by user ID, or "guest" |
| `orderby` | string | created_at | Sort column: created_at, user_id, route |
| `order` | string | DESC | Sort direction: ASC, DESC |

**GET /stats**

| Param | Type | Description |
|-------|------|-------------|
| `date_from` | string | Start date or datetime |
| `date_to` | string | End date or datetime |

Returns: `total_requests`, `success_count`, `error_count`, `success_rate`, `unique_sessions`, `by_tool`.

**GET /sessions/{id}**

| Param | Type | Default | Description |
|-------|------|---------|-------------|
| `page` | integer | 1 | Page number |
| `per_page` | integer | 50 | Results per page |
| `exclude_bodies` | boolean | false | Strip request/response bodies for lighter payloads |

**GET /search**

| Param | Type | Description |
|-------|------|-------------|
| `query` | string | Search keyword (required) |
| `page` | integer | Page number |
| `per_page` | integer | Results per page |

Searches across route, tool_name, request_body, and response_body.

**GET /errors**

| Param | Type | Default | Description |
|-------|------|---------|-------------|
| `limit` | integer | 20 | Number of errors to return (1-500) |

**GET /tool-performance**

| Param | Type | Description |
|-------|------|-------------|
| `tool_name` | string | Optional filter for a single tool |

Returns per-tool: `total_calls`, `success_count`, `error_count`, `error_rate`, `unique_users`.

**DELETE /retention**

| Param | Type | Description |
|-------|------|-------------|
| `before_date` | string | Delete all logs before this date (Y-m-d, required) |

## Authentication

### WordPress Application Passwords

Generate at Users > Your Profile > Application Passwords. Use via Basic Auth:

```bash
curl -u "admin:ABCD 1234 EFGH 5678" https://site.com/wp-json/activity-log-for-mcp/v1/requests
```

### WooCommerce API Keys

When WooCommerce is active, API keys work automatically:

```bash
# Query string
curl "https://site.com/wp-json/activity-log-for-mcp/v1/requests?consumer_key=ck_xxx&consumer_secret=cs_xxx"

# Basic Auth
curl -u "ck_xxx:cs_xxx" https://site.com/wp-json/activity-log-for-mcp/v1/requests
```

The WC key must belong to a user with `manage_options` capability. Read-only keys can access GET endpoints; read_write keys can access all endpoints.

## MCP Abilities

The plugin registers 7 abilities on an MCP server (via the `mcp_adapter_init` hook) under the `activity-log-for-mcp` category. All abilities require `manage_options` capability.

### activity-log-for-mcp/get-activity

Retrieve a paginated log of MCP interactions with optional filters.

**Input:**

| Param | Type | Default | Description |
|-------|------|---------|-------------|
| `page` | integer | 1 | Page number |
| `per_page` | integer | 10 | Results per page |
| `tool` | string | | Filter by tool name |
| `user_id` | integer | | Filter by WordPress user ID |
| `date_from` | string (date) | | Start date (Y-m-d) or datetime (Y-m-d H:i:s) |
| `date_to` | string (date) | | End date or datetime |

**Output:**

```json
{
  "data": [ { "id": 1, "route": "/woocommerce/mcp", "tool_name": "...", ... } ],
  "total": 42
}
```

### activity-log-for-mcp/get-stats

Get summary statistics. Useful for quick health checks without paginating all logs.

**Input:**

| Param | Type | Description |
|-------|------|-------------|
| `date_from` | string (date) | Optional start date or datetime |
| `date_to` | string (date) | Optional end date or datetime |

**Output:**

```json
{
  "total_requests": 150,
  "success_count": 140,
  "error_count": 3,
  "success_rate": 93.3,
  "unique_sessions": 12,
  "by_tool": [
    { "tool_name": "my-tool", "count": "85" }
  ]
}
```

### activity-log-for-mcp/get-activity-by-session

Retrieve all log entries for a specific MCP session, ordered chronologically. Use `exclude_bodies` to get a lightweight summary when payloads are large.

**Input:**

| Param | Type | Default | Description |
|-------|------|---------|-------------|
| `session_id` | string | | **Required.** The MCP session ID |
| `page` | integer | 1 | Page number |
| `per_page` | integer | 50 | Results per page |
| `exclude_bodies` | boolean | false | If true, omits headers, request_body, and response_body |

**Output:**

```json
{
  "data": [ { "id": 5, "route": "...", "tool_name": "...", ... } ],
  "total": 12
}
```

When `exclude_bodies` is true, each entry contains only: id, route, server_namespace, tool_name, user_id, method, mcp_session_id, response_status, tool_status, created_at.

### activity-log-for-mcp/search-activity

Full-text search across routes, tool names, request bodies, and response bodies.

**Input:**

| Param | Type | Default | Description |
|-------|------|---------|-------------|
| `query` | string | | **Required.** Search keyword |
| `page` | integer | 1 | Page number |
| `per_page` | integer | 10 | Results per page |

**Output:**

```json
{
  "data": [ { "id": 7, "route": "...", "request_body": "...matched...", ... } ],
  "total": 3
}
```

### activity-log-for-mcp/analyze-errors

List recent failed tool executions (tool_status = error) and HTTP errors (response_status >= 400).

**Input:**

| Param | Type | Default | Description |
|-------|------|---------|-------------|
| `limit` | integer | 20 | Number of errors to return |

**Output:** Array of full log entry objects, newest first.

### activity-log-for-mcp/get-tool-performance

Per-tool metrics: call count, success/error breakdown, error rate, and unique users. Optionally filter to a single tool.

**Input:**

| Param | Type | Description |
|-------|------|-------------|
| `tool_name` | string | Optional. Filter metrics to a single tool name |

**Output:**

```json
[
  {
    "tool_name": "my-tool",
    "total_calls": 85,
    "success_count": 80,
    "error_count": 5,
    "error_rate": 5.9,
    "unique_users": 3
  }
]
```

### activity-log-for-mcp/clear-old-logs

Delete log entries older than a specified date. For retention management.

**Input:**

| Param | Type | Description |
|-------|------|-------------|
| `before_date` | string (date) | **Required.** Delete all logs before this date (Y-m-d) |

**Output:**

```json
{
  "deleted": 42
}
```

## License

GPL v2 or later.
