Skip to content

Commit ababe88

Browse files
committed
feat: migrate to slog, add tracing, log masking and E2E workflow
- Migrate logging from logrus to slog for structured logs. - Add W3C Trace Context support and propagation. - Implement sensitive data masking and log body truncation. - Enrich channel information with team and creator names. - Add E2E testing framework and GitHub workflow. - Update README with new security and logging features.
1 parent 9bf3810 commit ababe88

16 files changed

Lines changed: 2053 additions & 217 deletions

File tree

.github/workflows/e2e.yml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
name: E2E Tests
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
debug:
7+
description: 'Run in debug mode (in-process, no Docker)'
8+
required: false
9+
default: 'false'
10+
type: choice
11+
options:
12+
- 'true'
13+
- 'false'
14+
15+
permissions:
16+
contents: read
17+
18+
jobs:
19+
e2e:
20+
runs-on: ubuntu-latest
21+
if: ${{ vars.ENABLE_E2E_TESTS == 'true' || github.event_name == 'workflow_dispatch' }}
22+
23+
steps:
24+
- name: Check out code
25+
uses: actions/checkout@v4
26+
27+
- name: Set up Go
28+
uses: actions/setup-go@v5
29+
with:
30+
go-version-file: "go.mod"
31+
32+
- name: Download dependencies
33+
run: go mod download
34+
35+
- name: Set up Docker Buildx
36+
if: ${{ github.event.inputs.debug != 'true' }}
37+
uses: docker/setup-buildx-action@v3
38+
39+
- name: Build Docker image
40+
if: ${{ github.event.inputs.debug != 'true' }}
41+
run: docker build -t flashcat/e2e-flashduty-mcp-server .
42+
43+
- name: Run E2E tests
44+
env:
45+
FLASHDUTY_E2E_APP_KEY: ${{ secrets.FLASHDUTY_E2E_APP_KEY }}
46+
FLASHDUTY_E2E_BASE_URL: ${{ secrets.FLASHDUTY_E2E_BASE_URL }}
47+
FLASHDUTY_E2E_DEBUG: ${{ github.event.inputs.debug }}
48+
run: |
49+
if [ -z "$FLASHDUTY_E2E_APP_KEY" ]; then
50+
echo "Error: FLASHDUTY_E2E_APP_KEY secret is not set"
51+
exit 1
52+
fi
53+
go test -v --tags e2e ./e2e/... -timeout 10m

README.md

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ For Cursors that support Remote MCP, use the following configuration:
3636
"mcpServers": {
3737
"flashduty": {
3838
"url": "https://mcp.flashcat.cloud/mcp",
39-
"authorization_token": "Bearer <your_flashduty_app_key>"
39+
"headers": {
40+
"Authorization": "Bearer <your_flashduty_app_key>"
41+
}
4042
}
4143
}
4244
}
@@ -146,12 +148,15 @@ Here is an example of configuring the remote service, specifying toolsets and re
146148
"mcpServers": {
147149
"flashduty": {
148150
"url": "https://mcp.flashcat.cloud/mcp?toolsets=incidents,users&read_only=true",
149-
"authorization_token": "Bearer <your_flashduty_app_key>"
151+
"headers": {
152+
"Authorization": "Bearer <your_flashduty_app_key>"
153+
}
150154
}
151155
}
152156
}
153157
```
154158

159+
- `headers.Authorization`: Your Flashduty APP key for authentication, prefixed with `Bearer `.
155160
- `toolsets=...`: Use a comma-separated list to specify the toolsets to enable (e.g., `incidents,users,channels`).
156161
- `read_only=true`: Enables read-only mode.
157162

@@ -257,6 +262,14 @@ Create `flashduty-mcp-server-config.json` in the same directory as the binary:
257262
export FLASHDUTY_MCP_TOOL_CREATE_INCIDENT_DESCRIPTION="an alternative description"
258263
```
259264

265+
#### 5. Logging & Security
266+
267+
The server provides structured logging and built-in security features:
268+
269+
- **Data Masking**: Sensitive information such as `APP_KEY` and `Authorization` headers are automatically masked in logs to prevent accidental credential leakage.
270+
- **Log Truncation**: Large request/response bodies are automatically truncated in logs (default 2KB) to maintain performance.
271+
- **W3C Trace Context**: Supports W3C Trace Context (`traceparent`) for end-to-end observability. Trace IDs are automatically included in logs for easy request tracking.
272+
260273
---
261274

262275
## Available Toolsets
@@ -300,7 +313,7 @@ The following toolsets are available (all are on by default). You can also use `
300313
- `query_teams` - Query teams with member details
301314

302315
### `channels` - Collaboration Space and Escalation Rules (2 tools)
303-
- `query_channels` - Query collaboration spaces
316+
- `query_channels` - Query collaboration spaces with enriched data (team and creator names)
304317
- `query_escalation_rules` - Query escalation rules for a channel
305318

306319
### `fields` - Custom Field Definitions (1 tool)

README_zh.md

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ Flashduty MCP Server 是一个基于 [Model Context Protocol (MCP)](https://mode
3434
"mcpServers": {
3535
"flashduty": {
3636
"url": "https://mcp.flashcat.cloud/mcp",
37-
"authorization_token": "Bearer <your_flashduty_app_key>"
37+
"headers": {
38+
"Authorization": "Bearer <your_flashduty_app_key>"
39+
}
3840
}
3941
}
4042
}
@@ -133,12 +135,15 @@ Flashduty MCP Server 支持以下配置:
133135
"mcpServers": {
134136
"flashduty": {
135137
"url": "https://mcp.flashcat.cloud/mcp?toolsets=incidents,users&read_only=true",
136-
"authorization_token": "Bearer <your_flashduty_app_key>"
138+
"headers": {
139+
"Authorization": "Bearer <your_flashduty_app_key>"
140+
}
137141
}
138142
}
139143
}
140144
```
141145

146+
- `headers.Authorization`:用于认证的 Flashduty APP Key,需添加 `Bearer ` 前缀
142147
- `toolsets=...`:启用指定的工具集,多个用逗号分隔
143148
- `read_only=true`:启用只读模式
144149

@@ -236,6 +241,14 @@ export FLASHDUTY_OUTPUT_FORMAT=toon
236241
export FLASHDUTY_MCP_TOOL_CREATE_INCIDENT_DESCRIPTION="自定义描述"
237242
```
238243

244+
#### 5. 日志与安全
245+
246+
服务内置了结构化日志和增强的安全特性:
247+
248+
- **数据脱敏**:日志会自动对敏感信息(如 `APP_KEY``Authorization` 请求头)进行掩码处理,防止密钥泄露。
249+
- **日志截断**:对于过大的请求/响应体,日志会自动进行截断(默认 2KB),确保服务性能。
250+
- **链路追踪**:支持 W3C Trace Context 标准。日志中会自动关联 `trace_id`,方便跨服务追踪请求全链路趋势。
251+
239252
---
240253

241254
## 工具集
@@ -279,7 +292,7 @@ export FLASHDUTY_MCP_TOOL_CREATE_INCIDENT_DESCRIPTION="自定义描述"
279292
- `query_teams` - 查询团队(含成员详情)
280293

281294
### `channels` - 协作空间 (2)
282-
- `query_channels` - 查询协作空间
295+
- `query_channels` - 查询协作空间(含团队、创建者名称等富化信息)
283296
- `query_escalation_rules` - 查询分派规则
284297

285298
### `fields` - 字段管理 (1)

e2e/README.md

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# End To End (e2e) Tests
2+
3+
The purpose of the E2E tests is to provide confidence in the black box behavior of the flashduty-mcp-server artifacts. It does this by:
4+
5+
* Building the `flashduty-mcp-server` docker image
6+
* Running the image
7+
* Interacting with the server via stdio
8+
* Issuing requests that interact with the live Flashduty API
9+
10+
## Running the Tests
11+
12+
A service must be running that supports image building and container creation via the `docker` CLI.
13+
14+
Since these tests require an APP key to interact with real resources on the Flashduty API, it is gated behind the `e2e` build flag.
15+
16+
```bash
17+
FLASHDUTY_E2E_APP_KEY=<YOUR_APP_KEY> go test -v --tags e2e ./e2e
18+
```
19+
20+
### Environment Variables
21+
22+
| Variable | Required | Description |
23+
|----------|----------|-------------|
24+
| `FLASHDUTY_E2E_APP_KEY` | Yes | APP key for authenticating with Flashduty API |
25+
| `FLASHDUTY_E2E_BASE_URL` | No | Base URL for Flashduty API (default: `https://api.flashcat.cloud`) |
26+
| `FLASHDUTY_E2E_DEBUG` | No | Set to any value to run tests in debug mode (in-process) |
27+
28+
### Debug Mode
29+
30+
By default, the tests build and run a Docker container to test the server as a black box. However, for easier debugging, you can run the server in-process by setting `FLASHDUTY_E2E_DEBUG`:
31+
32+
```bash
33+
FLASHDUTY_E2E_APP_KEY=<YOUR_APP_KEY> FLASHDUTY_E2E_DEBUG=true go test -v --tags e2e ./e2e
34+
```
35+
36+
This allows you to:
37+
- Set breakpoints in the MCP server code
38+
- Get better visibility into failures
39+
- Skip the Docker build step for faster iteration
40+
41+
Note: Debug mode has slightly reduced coverage as it doesn't test Docker integration or cobra/viper configuration parsing.
42+
43+
## Test Coverage
44+
45+
### Basic Tests
46+
47+
- **TestInitialize**: Verifies server startup and tool listing
48+
- **TestToolsets**: Tests that toolset filtering works correctly
49+
- **TestReadOnlyMode**: Tests that read-only mode only exposes read tools
50+
51+
### Read-Only Tools Tests
52+
53+
- **TestQueryIncidents**: Tests querying incidents
54+
- **TestQueryChannels**: Tests querying collaboration spaces
55+
- **TestQueryMembers**: Tests querying members
56+
57+
### Incident Lifecycle Tests
58+
59+
- **TestIncidentLifecycle**: Tests the full incident lifecycle (create → acknowledge → close)
60+
61+
## Limitations
62+
63+
1. **Resource Cleanup**: Unlike GitHub's API, Flashduty doesn't support deleting incidents or collaboration spaces. Tests that create resources will close them instead of deleting them.
64+
65+
2. **Test Account**: It's recommended to use a dedicated test APP key to avoid polluting production data.
66+
67+
3. **Rate Limiting**: Be aware of Flashduty API rate limits when running tests frequently.
68+
69+
4. **Global State**: Some operations may affect the global state of your Flashduty account. Use with caution on production accounts.
70+
71+
## CI Integration
72+
73+
The e2e tests can be run in GitHub Actions via the `e2e.yml` workflow.
74+
75+
### Setup
76+
77+
1. Add the following secrets to your repository:
78+
- `FLASHDUTY_E2E_APP_KEY`: Your Flashduty APP key for testing
79+
- `FLASHDUTY_E2E_BASE_URL` (optional): Custom API base URL
80+
81+
2. Optionally, set the repository variable `ENABLE_E2E_TESTS=true` to enable automatic runs.
82+
83+
3. Run the workflow manually from the Actions tab, or trigger it via the GitHub API.
84+
85+
### Manual Trigger
86+
87+
You can trigger the workflow manually with debug mode:
88+
89+
```bash
90+
gh workflow run e2e.yml -f debug=true
91+
```
92+
93+
## Adding New Tests
94+
95+
When adding new tests:
96+
97+
1. Use the `t.Parallel()` directive for tests that can run concurrently
98+
2. Use `callTool()` helper for making tool calls
99+
3. Use `unmarshalToolResponse()` for parsing responses
100+
4. For tests that create resources, ensure proper cleanup in `t.Cleanup()`
101+
5. Consider using the native API client (`getAPIClient()`) for verification

0 commit comments

Comments
 (0)