docs : add HTTP transport + API token auth to MCP spec

Both STDIO (local) and HTTP (LAN) transports are now in scope.
HTTP secured by API token on User entity with custom authenticator.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-15 19:15:20 +01:00
parent 8d24949186
commit 9e19adc09a

View File

@@ -8,8 +8,11 @@
Lesstime is a project management app (Symfony 8 + API Platform 4). We want AI assistants to interact with projects, tasks, and time entries via the Model Context Protocol (MCP).
**Phase 1 (this spec)**: STDIO transport for Claude Code local usage.
**Phase 2 (future)**: HTTP transport + API token auth + Cloudflare Tunnel for remote clients (Claude Web, ChatGPT, Codex).
Both transports are implemented together:
- **STDIO**: Claude Code on the same machine (local dev, `php bin/console mcp:server`)
- **HTTP**: Claude Code or any MCP client on the LAN (`http://<server-ip>:8082/_mcp`), secured by API token
Future: Cloudflare Tunnel for internet-facing access (Claude Web, ChatGPT, Codex).
## Technology Choice
@@ -69,13 +72,31 @@ mcp:
Use list-users and list-clients to discover valid user and client IDs.
client_transports:
stdio: true
http: false # Phase 2
http: true
http:
path: /_mcp
session:
store: file
directory: '%kernel.cache_dir%/mcp-sessions'
ttl: 3600
```
### Nginx Configuration
Add a location block to pass `/_mcp` requests to Symfony (same pattern as `/api`):
```nginx
location /_mcp {
try_files $uri /index.php$is_args$args;
}
```
### Claude Code Configuration
**Option A — Local (STDIO, same machine):**
```json
// .claude/settings.json or project settings
{
"mcpServers": {
"lesstime": {
@@ -87,13 +108,38 @@ mcp:
}
```
Note: The app runs in Docker (`php-lesstime-fpm` container), so the command uses `docker exec` to run inside the container.
**Option B — Network (HTTP, another machine on LAN):**
### Security Model (Phase 1)
```json
{
"mcpServers": {
"lesstime": {
"type": "url",
"url": "http://192.168.x.x:8082/_mcp",
"headers": {
"Authorization": "Bearer <api-token>"
}
}
}
}
```
Phase 1 uses STDIO transport only (Claude Code local). The console command runs without a Symfony security context. All tools run with **full privileges** (equivalent to ROLE_ADMIN), since only the local developer has access. No authentication is needed.
### Security Model
Phase 2 will add API token authentication on the HTTP transport.
**STDIO transport**: No authentication. The console command runs locally with full privileges (equivalent to ROLE_ADMIN). Only the local developer has access.
**HTTP transport**: Secured by API token. A new `apiToken` field on the `User` entity stores a unique token per user. A custom Symfony authenticator (`ApiTokenAuthenticator`) checks the `Authorization: Bearer <token>` header on `/_mcp` requests and authenticates as the corresponding user.
#### API Token Implementation
1. **Entity change**: Add `apiToken` (string, unique, nullable) to `User` + Doctrine migration
2. **Authenticator**: `src/Security/ApiTokenAuthenticator.php` — a Symfony custom authenticator that:
- Extracts the token from the `Authorization` header
- Looks up the user by `apiToken`
- Returns 401 if token missing/invalid
3. **Firewall**: New firewall entry in `config/packages/security.yaml` for `/_mcp` path, before the main `api` firewall
4. **Token generation**: A console command `app:generate-api-token <username>` to generate/regenerate tokens
5. **Fixtures**: Add an API token to the admin fixture user for dev/testing
## Tools Specification
@@ -406,21 +452,21 @@ class ListTasksTool
## Installation Steps
1. `composer require symfony/mcp-bundle` (inside Docker container)
2. Create `config/packages/mcp.yaml` with STDIO transport
3. Create tool classes in `src/Mcp/Tool/`
4. Test with `php bin/console mcp:server` (STDIO)
5. Configure Claude Code settings to point to the MCP server
2. Create `config/packages/mcp.yaml` with STDIO + HTTP transports
3. Add MCP route: `config/routes/mcp.yaml`
4. Add Nginx location block for `/_mcp`
5. Add `apiToken` field to `User` entity + migration
6. Create `ApiTokenAuthenticator` + security firewall for `/_mcp`
7. Create `app:generate-api-token` console command
8. Update fixtures with API token for admin user
9. Create tool classes in `src/Mcp/Tool/`
10. Test STDIO: `php bin/console mcp:server`
11. Test HTTP: `curl -H "Authorization: Bearer <token>" http://localhost:8082/_mcp`
12. Configure Claude Code settings (STDIO local or HTTP network)
Note: STDIO transport does not need HTTP routes. Routes are only needed for Phase 2 (HTTP transport).
## Future
## Phase 2 (Future)
When ready for internet-facing access:
When ready for remote clients:
1. Enable HTTP transport on `/_mcp`
2. Add MCP route: `config/routes/mcp.yaml`
3. Add `apiToken` field on `User` entity + migration
4. Create `ApiTokenAuthenticator` (Symfony custom authenticator)
5. Add firewall rule for `/_mcp` path
6. Set up Cloudflare Tunnel for external access
7. Configure Claude Web / ChatGPT / Codex with the tunnel URL + token
1. Set up Cloudflare Tunnel for external access
2. Configure Claude Web / ChatGPT / Codex with the tunnel URL + token