Merge development into main: MCP server documentation (#111)
Lint / PHP (phpcs PSR-12) (push) Successful in 21s
Lint / JS (eslint) (push) Successful in 13s
Lint / PHP requirements (version + extensions) (push) Successful in 49s
Lint / Notify on failure (push) Skipped
Security / PHP Security (semgrep) (push) Successful in 1m55s
Lint / Deploy (push) Successful in 2s
Lint / PHP (phpcs PSR-12) (push) Successful in 21s
Lint / JS (eslint) (push) Successful in 13s
Lint / PHP requirements (version + extensions) (push) Successful in 49s
Lint / Notify on failure (push) Skipped
Security / PHP Security (semgrep) (push) Successful in 1m55s
Lint / Deploy (push) Successful in 2s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MGDKHiU5RJdo3dqQUDow3X
This commit is contained in:
@@ -113,6 +113,33 @@ All Bearer-authenticated, rate-limited, and (like `create_ticket_api.php`) exemp
|
||||
| `/api/ticket_comment_api.php` | POST | read_write | Add a comment: `{ticket_id, comment_text, markdown_enabled?}` |
|
||||
| `/api/ticket_status_api.php` | POST | read_write | Change/close status (workflow-validated): `{ticket_id, status, comment?}` — `comment` is required for transitions that require one (e.g. → Closed); it is posted as the close reason in the same call |
|
||||
|
||||
### MCP server (Claude Code and other MCP clients)
|
||||
`/mcp` is a remote [MCP](https://modelcontextprotocol.io) server (Streamable HTTP) protected by **OAuth via Authelia** — no API keys. You sign in once in the browser and every action runs **as you**: the same visibility, permissions, Workflow Designer rules, audit log and notifications as the web UI.
|
||||
|
||||
**Connect Claude Code** (one-time):
|
||||
```bash
|
||||
claude mcp add --transport http --scope user \
|
||||
--client-id tinker-tickets-mcp --callback-port 47823 \
|
||||
tinker https://t.lotusguild.org/mcp
|
||||
claude mcp login tinker # add --no-browser on a headless machine, then paste the redirect URL back
|
||||
```
|
||||
`--client-id` / `--callback-port 47823` are required: Authelia doesn't support dynamic client registration, so Claude Code uses the pre-registered public client `tinker-tickets-mcp`, whose only allowed redirect is `http://localhost:47823/callback`. Access requires the same `admin`/`employee` group as the web UI. Tokens refresh automatically (refresh token lasts 30 days); `claude mcp logout tinker` signs out.
|
||||
|
||||
| Tool | Scope | What it does |
|
||||
|------|-------|--------------|
|
||||
| `search_tickets` | `tickets:read` | Search/list tickets you can see (text, status, priority, category, assignee `me`/`unassigned`/username), paginated |
|
||||
| `get_ticket` | `tickets:read` | One ticket's details + comments |
|
||||
| `create_ticket` | `tickets:write` | Create a ticket (title, description, priority, category, type, visibility, assignee) |
|
||||
| `add_comment` | `tickets:write` | Comment (markdown, @mentions, replies) |
|
||||
| `update_status` | `tickets:write` | Workflow-validated status change; `comment` required when the transition requires one |
|
||||
| `assign_ticket` | `tickets:write` | Assign / unassign (admin, creator, or current assignee only) |
|
||||
|
||||
How it fits together (see issue #111 for the full design):
|
||||
- **Authelia** is the authorization server: client `tinker-tickets-mcp`, custom scopes `tickets:read`/`tickets:write`, RS256 JWT access tokens carrying `preferred_username`/`groups`. Needs Authelia **≠ 4.39.21/4.39.22** (RFC 8707 `resource` bug); 4.39.20 or ≥ 4.39.23 are fine.
|
||||
- **`mcp/server.php`** is the resource server (official `mcp/sdk`, pinned). It validates each token's signature (JWKS), issuer, **audience = this server's URL** (`MCP_RESOURCE_URL`, derived from `APP_DOMAIN`, so a beta token can't be used on prod) and expiry, then maps the user with the same rules as the web login. It serves RFC 9728 metadata at `/.well-known/oauth-protected-resource/mcp`.
|
||||
- **Composer is used only by the MCP endpoint** (`vendor/` is gitignored and installed by the deploy script with `composer install --no-dev`); nothing else in the app loads it.
|
||||
- **Reverse proxy:** `/mcp` and `/.well-known/oauth-protected-resource` are exempt from Authelia forward-auth (the token is the credential) and have `Remote-*` headers blanked; `vendor/`, `mcp/` and `composer.*` are never served.
|
||||
|
||||
### User Management & Authentication
|
||||
- **SSO Integration**: Authelia authentication with LLDAP backend
|
||||
- **Role-Based Access**: Admin and standard user roles
|
||||
@@ -355,7 +382,9 @@ tinker_tickets/
|
||||
│ ├── config.php # Config + .env loading
|
||||
│ └── requirements.php # PHP version/extension requirements (single source of
|
||||
│ # truth for scripts/check_requirements.php + api/health.php)
|
||||
├── composer.json / composer.lock # MCP endpoint dependencies only (mcp/sdk pinned); vendor/ installed at deploy
|
||||
├── controllers/
|
||||
│ ├── ApiTicketController.php # Partial ticket updates (status/fields/visibility), shared by update_ticket.php + MCP
|
||||
│ ├── CommentController.php # Comment create/edit/delete + notifications
|
||||
│ ├── DashboardController.php # Dashboard with stats + filters
|
||||
│ └── TicketController.php # Ticket CRUD + timeline + visibility
|
||||
@@ -399,11 +428,24 @@ tinker_tickets/
|
||||
│ ├── 002_fix_collation_consistency.sql # Upgrade-only (already in baseline for fresh installs)
|
||||
│ ├── 003_fk_on_delete_set_null.sql # Upgrade-only (already in baseline for fresh installs)
|
||||
│ ├── 004_fix_ticket_watchers_type.sql # Upgrade-only (already in baseline for fresh installs)
|
||||
│ ├── 005_attachment_thumbnails.sql # ticket_attachments.thumbnail_filename
|
||||
│ ├── 006_api_key_visibility_scope.sql # api_keys.see_all_visibility (public-only by default)
|
||||
│ ├── 007_notification_retry_queue.sql # Queue for failed Matrix webhook retries
|
||||
│ └── migrate.php # CLI migration runner (tracks applied migrations)
|
||||
├── mcp/
|
||||
│ ├── server.php # MCP endpoint (/mcp): OAuth resource server; only file that loads vendor/
|
||||
│ └── src/
|
||||
│ ├── Auth/ # IdentityMiddleware (token -> user), ToolScopeMiddleware, McpIdentity
|
||||
│ ├── Tools/ # TicketReadTools, TicketWriteTools
|
||||
│ └── ToolCatalog.php # Tool registry + which tools need tickets:write
|
||||
├── scripts/
|
||||
│ ├── check_requirements.php # Verify PHP extensions/config prerequisites
|
||||
│ └── cleanup_orphan_uploads.php # Delete orphaned upload files past grace period (cron)
|
||||
├── uploads/ # File attachment storage
|
||||
├── services/
|
||||
│ ├── AssignmentService.php # Assign/unassign (shared by assign_ticket.php + MCP)
|
||||
│ ├── CommentService.php # Add comment + mentions/notifications (shared by add_comment.php + MCP)
|
||||
│ └── TicketCreationService.php # Create ticket (shared by TicketController + MCP)
|
||||
├── uploads/ # File attachment storage (served only via PHP; nginx: internal)
|
||||
│ └── avatars/ # lldap avatar disk cache
|
||||
├── views/
|
||||
│ ├── admin/
|
||||
|
||||
Reference in New Issue
Block a user