tracecat-mcp-community 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +7 -0
- package/LICENSE +21 -0
- package/README.md +267 -0
- package/dist/client.d.ts +26 -0
- package/dist/client.js +147 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +32 -0
- package/dist/minimal.d.ts +1 -0
- package/dist/minimal.js +8 -0
- package/dist/minimal.js.backup +8 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.js +32 -0
- package/dist/tools/actions.d.ts +3 -0
- package/dist/tools/actions.js +54 -0
- package/dist/tools/cases.d.ts +3 -0
- package/dist/tools/cases.js +73 -0
- package/dist/tools/docs.d.ts +3 -0
- package/dist/tools/docs.js +389 -0
- package/dist/tools/executions.d.ts +3 -0
- package/dist/tools/executions.js +40 -0
- package/dist/tools/graph.d.ts +3 -0
- package/dist/tools/graph.js +82 -0
- package/dist/tools/schedules.d.ts +3 -0
- package/dist/tools/schedules.js +52 -0
- package/dist/tools/secrets.d.ts +3 -0
- package/dist/tools/secrets.js +56 -0
- package/dist/tools/system.d.ts +3 -0
- package/dist/tools/system.js +16 -0
- package/dist/tools/tables.d.ts +3 -0
- package/dist/tools/tables.js +102 -0
- package/dist/tools/templates.d.ts +3 -0
- package/dist/tools/templates.js +547 -0
- package/dist/tools/webhooks.d.ts +3 -0
- package/dist/tools/webhooks.js +9 -0
- package/dist/tools/workflows.d.ts +3 -0
- package/dist/tools/workflows.js +318 -0
- package/dist/types.d.ts +78 -0
- package/dist/types.js +1 -0
- package/package.json +56 -0
package/.env.example
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
## Tracecat MCP Server - Credentials
|
|
2
|
+
## Copy this file to .env and fill in your values.
|
|
3
|
+
## DO NOT commit .env to version control.
|
|
4
|
+
TRACECAT_API_URL=http://localhost/api
|
|
5
|
+
TRACECAT_USERNAME=your-email@example.com
|
|
6
|
+
TRACECAT_PASSWORD=your-password-here
|
|
7
|
+
TRACECAT_WORKSPACE_ID=
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 adrojis
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="assets/banner.png" alt="Tracecat MCP Banner" width="100%">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# tracecat-mcp-community
|
|
6
|
+
|
|
7
|
+
**A Model Context Protocol (MCP) server for the [Tracecat](https://tracecat.com) SOAR platform — 49 tools across 12 domains.**
|
|
8
|
+
|
|
9
|
+
[](LICENSE)
|
|
10
|
+
[](https://www.npmjs.com/package/tracecat-mcp-community)
|
|
11
|
+
[](https://nodejs.org)
|
|
12
|
+
[](https://github.com/adrojis/tracecat-mcp-community/actions/workflows/ci.yml)
|
|
13
|
+
[](https://github.com/TracecatHQ/tracecat)
|
|
14
|
+
[](https://modelcontextprotocol.io)
|
|
15
|
+
[](#docker)
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## What is this?
|
|
20
|
+
|
|
21
|
+
An [MCP server](https://modelcontextprotocol.io) that gives AI assistants (Claude Code, Claude Desktop, etc.) full control over a [Tracecat](https://github.com/TracecatHQ/tracecat) instance through natural language. Manage workflows, actions, cases, secrets, tables, schedules, and more — without leaving your editor.
|
|
22
|
+
|
|
23
|
+
- **49 tools** covering the full Tracecat API surface
|
|
24
|
+
- **Lazy authentication** — MCP transport starts instantly, login happens on first tool call
|
|
25
|
+
- **Auto workspace detection** — no manual workspace ID needed
|
|
26
|
+
- **Session cookie auth** — handles Tracecat's cookie-based auth transparently
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Tools
|
|
31
|
+
|
|
32
|
+
| Domain | Tools | Description |
|
|
33
|
+
|---|---|---|
|
|
34
|
+
| **Workflows** | 9 | List, create, get, update, deploy, export, delete, validate, autofix |
|
|
35
|
+
| **Actions** | 5 | List, create, get, update, delete workflow actions |
|
|
36
|
+
| **Executions** | 5 | Run workflows, list/get/cancel executions, compact view |
|
|
37
|
+
| **Cases** | 7 | List, create, get, update, delete cases; add/list comments |
|
|
38
|
+
| **Secrets** | 5 | Search, create, get, update, delete secrets |
|
|
39
|
+
| **Tables** | 5 | List, create, get, update, delete tables |
|
|
40
|
+
| **Columns** | 2 | Create, delete table columns |
|
|
41
|
+
| **Rows** | 6 | List, get, insert, update, delete, batch insert rows |
|
|
42
|
+
| **Schedules** | 5 | List, create, get, update, delete schedules |
|
|
43
|
+
| **Graph** | 3 | Add edges, move nodes, update trigger position |
|
|
44
|
+
| **Webhooks** | 1 | Generate/rotate webhook API keys |
|
|
45
|
+
| **Docs** | 2 | Search Tracecat docs, list available tool documentation |
|
|
46
|
+
| **Templates** | 2 | List and get community workflow templates |
|
|
47
|
+
| **System** | 1 | Health check |
|
|
48
|
+
|
|
49
|
+
> **Total: 49 tools** for complete Tracecat automation.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Quick Start
|
|
54
|
+
|
|
55
|
+
### Option A: npx (fastest)
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# Install globally
|
|
59
|
+
npm install -g tracecat-mcp-community
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Create a `.env` file wherever you run from (or in the package directory):
|
|
63
|
+
|
|
64
|
+
```env
|
|
65
|
+
TRACECAT_API_URL=http://localhost/api
|
|
66
|
+
TRACECAT_USERNAME=your-email@example.com
|
|
67
|
+
TRACECAT_PASSWORD=your-password-here
|
|
68
|
+
TRACECAT_WORKSPACE_ID= # Optional — auto-detected if omitted
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Add to your `.mcp.json`:
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"mcpServers": {
|
|
76
|
+
"tracecat": {
|
|
77
|
+
"command": "npx",
|
|
78
|
+
"args": ["-y", "tracecat-mcp-community"]
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Option B: From source
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
git clone https://github.com/adrojis/tracecat-mcp-community.git
|
|
88
|
+
cd tracecat-mcp-community
|
|
89
|
+
npm install
|
|
90
|
+
cp .env.example .env # Edit with your credentials
|
|
91
|
+
npm run build
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Add to your `.mcp.json`:
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"mcpServers": {
|
|
99
|
+
"tracecat": {
|
|
100
|
+
"command": "node",
|
|
101
|
+
"args": ["/absolute/path/to/tracecat-mcp-community/dist/index.js"]
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Option C: Docker
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
git clone https://github.com/adrojis/tracecat-mcp-community.git
|
|
111
|
+
cd tracecat-mcp-community
|
|
112
|
+
docker build -t tracecat-mcp-community .
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
{
|
|
117
|
+
"mcpServers": {
|
|
118
|
+
"tracecat": {
|
|
119
|
+
"command": "docker",
|
|
120
|
+
"args": ["run", "-i", "--rm", "--env-file", "/path/to/.env", "tracecat-mcp-community"]
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
> **Security:** `.env` is gitignored and never committed. Never hardcode credentials in source files. See [SECURITY.md](SECURITY.md).
|
|
127
|
+
|
|
128
|
+
Then restart Claude Code and verify with `/mcp` — you should see the `tracecat` server with 49 tools.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Configuration
|
|
133
|
+
|
|
134
|
+
| Variable | Required | Default | Description |
|
|
135
|
+
|---|---|---|---|
|
|
136
|
+
| `TRACECAT_API_URL` | No | `http://localhost/api` | Tracecat API base URL |
|
|
137
|
+
| `TRACECAT_USERNAME` | **Yes** | — | Login email |
|
|
138
|
+
| `TRACECAT_PASSWORD` | **Yes** | — | Login password |
|
|
139
|
+
| `TRACECAT_WORKSPACE_ID` | No | Auto-detected | Workspace ID (uses first workspace if omitted) |
|
|
140
|
+
|
|
141
|
+
Credentials are loaded from `.env` via [dotenv](https://github.com/motdotla/dotenv). The `.env` file must be in the project root (next to `package.json`).
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Architecture
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
src/
|
|
149
|
+
├── index.ts # Entry point — StdioTransport + env loading
|
|
150
|
+
├── server.ts # McpServer creation + tool registration
|
|
151
|
+
├── client.ts # HTTP client with lazy auth + auto workspace injection
|
|
152
|
+
├── types.ts # TypeScript interfaces
|
|
153
|
+
└── tools/
|
|
154
|
+
├── workflows.ts # Workflow CRUD + deploy/export/validate/autofix
|
|
155
|
+
├── actions.ts # Action CRUD with YAML inputs
|
|
156
|
+
├── cases.ts # Case management + comments
|
|
157
|
+
├── executions.ts # Run, list, cancel, inspect executions
|
|
158
|
+
├── secrets.ts # Secret management
|
|
159
|
+
├── tables.ts # Tables, columns, and rows
|
|
160
|
+
├── graph.ts # Graph operations (edges, node positions)
|
|
161
|
+
├── webhooks.ts # Webhook key rotation
|
|
162
|
+
├── schedules.ts # Cron/interval scheduling
|
|
163
|
+
├── docs.ts # Documentation search
|
|
164
|
+
├── templates.ts # Community workflow templates
|
|
165
|
+
└── system.ts # Health check
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Key Design Decisions
|
|
171
|
+
|
|
172
|
+
| Decision | Rationale |
|
|
173
|
+
|---|---|
|
|
174
|
+
| **Lazy initialization** | MCP transport starts immediately; login happens on first tool call. Avoids blocking Claude Code startup. |
|
|
175
|
+
| **Session cookies** | Tracecat currently uses `fastapiusersauth` cookies, not API keys. The client handles login and cookie extraction automatically. See note below on upcoming API token support. |
|
|
176
|
+
| **YAML string inputs** | Action `inputs` are sent as YAML strings per the Tracecat API contract, not JSON objects. |
|
|
177
|
+
| **POST for updates** | Actions, secrets, and schedules use `POST` for updates instead of the conventional `PATCH`. |
|
|
178
|
+
| **Auto workspace injection** | `workspace_id` is auto-detected and injected as a query parameter on every request. |
|
|
179
|
+
| **Optimistic locking** | Graph operations read `base_version` before patching to prevent concurrent edit conflicts. |
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Authentication Roadmap
|
|
184
|
+
|
|
185
|
+
This server currently authenticates via **username/password** (session cookies). The Tracecat team is actively working on **API token authentication**, which will provide a simpler and more secure connection method — no more password in `.env`.
|
|
186
|
+
|
|
187
|
+
We will add API token support as soon as it becomes available upstream. The username/password method will remain supported for backward compatibility.
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## API Quirks
|
|
192
|
+
|
|
193
|
+
These behaviors differ from typical REST conventions and are handled transparently by the server:
|
|
194
|
+
|
|
195
|
+
| Quirk | Details |
|
|
196
|
+
|---|---|
|
|
197
|
+
| `workspace_id` as query param | Must be `?workspace_id=...`, not a header |
|
|
198
|
+
| POST for updates | `/actions/{id}`, `/secrets/{id}`, `/schedules/{id}` use POST |
|
|
199
|
+
| Actions list endpoint | `GET /actions?workflow_id=...` (not nested under `/workflows`) |
|
|
200
|
+
| Action inputs format | YAML string, not JSON object |
|
|
201
|
+
| Workflow list pagination | Returns `{ items: [...], next_cursor }`, not a plain array |
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Development
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
# Watch mode (auto-reload)
|
|
209
|
+
npm run dev
|
|
210
|
+
|
|
211
|
+
# Build TypeScript
|
|
212
|
+
npm run build
|
|
213
|
+
|
|
214
|
+
# Run directly
|
|
215
|
+
node dist/index.js
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Testing
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
npm run build
|
|
222
|
+
npm test
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Tests use Node.js built-in test runner (no extra dependencies). See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
226
|
+
|
|
227
|
+
## MCP Inspector
|
|
228
|
+
|
|
229
|
+
The [MCP Inspector](https://github.com/modelcontextprotocol/inspector) is a visual debugging tool that lets you browse and test all 49 tools interactively in your browser — useful for verifying your setup, exploring tool schemas, and testing API calls without Claude.
|
|
230
|
+
|
|
231
|
+
From the project root:
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
npx @modelcontextprotocol/inspector node dist/index.js
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
This starts a local web UI (default: `http://localhost:6274`). Click the **Tools** tab to see all available tools, inspect their input schemas, and execute them against your Tracecat instance.
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## Roadmap
|
|
242
|
+
|
|
243
|
+
This project is under active development. Tracecat's API surface evolves fast, and we intend to keep up — expect new tools, refinements, and breaking-change adaptations as the platform matures.
|
|
244
|
+
|
|
245
|
+
Planned areas of improvement:
|
|
246
|
+
|
|
247
|
+
- **More tools** — covering new Tracecat API endpoints as they ship
|
|
248
|
+
- **Better error handling** — structured error responses with actionable hints
|
|
249
|
+
- **OAuth/OIDC support** — for Tracecat instances using SSO instead of basic auth
|
|
250
|
+
- **Test suite** — automated integration tests against a live Tracecat instance
|
|
251
|
+
|
|
252
|
+
Contributions, issues, and feature requests are welcome.
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Related Projects
|
|
257
|
+
|
|
258
|
+
- [tracecat-skills](https://github.com/adrojis/tracecat-skills) — Claude Code skills for Tracecat workflow building
|
|
259
|
+
> **Note:** This project was previously named `tracecat-mcp`. It has been renamed to `tracecat-mcp-community` to clearly distinguish it from [Tracecat's official MCP server](https://github.com/TracecatHQ/tracecat) which uses OAuth authentication.
|
|
260
|
+
- [Tracecat](https://github.com/TracecatHQ/tracecat) — The open-source SOAR platform
|
|
261
|
+
- [MCP SDK](https://github.com/modelcontextprotocol/typescript-sdk) — Model Context Protocol TypeScript SDK
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## License
|
|
266
|
+
|
|
267
|
+
[MIT](LICENSE)
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export declare class TracecatClient {
|
|
2
|
+
private baseUrl;
|
|
3
|
+
private workspaceId;
|
|
4
|
+
private sessionCookie;
|
|
5
|
+
private username;
|
|
6
|
+
private password;
|
|
7
|
+
private initialized;
|
|
8
|
+
private initPromise;
|
|
9
|
+
constructor(baseUrl: string, username: string, password: string, workspaceId?: string);
|
|
10
|
+
/** Ensures the client is logged in and workspace is set. Safe to call multiple times. */
|
|
11
|
+
ensureInitialized(): Promise<void>;
|
|
12
|
+
login(): Promise<void>;
|
|
13
|
+
private headers;
|
|
14
|
+
request<T = unknown>(method: string, path: string, body?: unknown, queryParams?: Record<string, string>): Promise<T>;
|
|
15
|
+
get<T = unknown>(path: string, queryParams?: Record<string, string>): Promise<T>;
|
|
16
|
+
post<T = unknown>(path: string, body?: unknown, queryParams?: Record<string, string>): Promise<T>;
|
|
17
|
+
patch<T = unknown>(path: string, body: unknown, queryParams?: Record<string, string>): Promise<T>;
|
|
18
|
+
delete<T = unknown>(path: string, queryParams?: Record<string, string>): Promise<T>;
|
|
19
|
+
initWorkspaceId(): Promise<void>;
|
|
20
|
+
getWorkspaceId(): string;
|
|
21
|
+
/** Fetch current graph then apply operations with optimistic locking */
|
|
22
|
+
patchGraph(workflowId: string, operations: Array<{
|
|
23
|
+
type: string;
|
|
24
|
+
payload: Record<string, unknown>;
|
|
25
|
+
}>): Promise<unknown>;
|
|
26
|
+
}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
export class TracecatClient {
|
|
2
|
+
baseUrl;
|
|
3
|
+
workspaceId;
|
|
4
|
+
sessionCookie = "";
|
|
5
|
+
username;
|
|
6
|
+
password;
|
|
7
|
+
initialized = false;
|
|
8
|
+
initPromise = null;
|
|
9
|
+
constructor(baseUrl, username, password, workspaceId = "") {
|
|
10
|
+
this.baseUrl = baseUrl.replace(/\/$/, "");
|
|
11
|
+
this.username = username;
|
|
12
|
+
this.password = password;
|
|
13
|
+
this.workspaceId = workspaceId;
|
|
14
|
+
}
|
|
15
|
+
/** Ensures the client is logged in and workspace is set. Safe to call multiple times. */
|
|
16
|
+
async ensureInitialized() {
|
|
17
|
+
if (this.initialized)
|
|
18
|
+
return;
|
|
19
|
+
if (!this.initPromise) {
|
|
20
|
+
this.initPromise = (async () => {
|
|
21
|
+
await this.login();
|
|
22
|
+
await this.initWorkspaceId();
|
|
23
|
+
this.initialized = true;
|
|
24
|
+
console.error("[tracecat-mcp-community] Login successful");
|
|
25
|
+
console.error(`[tracecat-mcp-community] Workspace: ${this.workspaceId || "(none)"}`);
|
|
26
|
+
})();
|
|
27
|
+
}
|
|
28
|
+
await this.initPromise;
|
|
29
|
+
}
|
|
30
|
+
async login() {
|
|
31
|
+
const formData = new URLSearchParams();
|
|
32
|
+
formData.append("username", this.username);
|
|
33
|
+
formData.append("password", this.password);
|
|
34
|
+
const response = await fetch(`${this.baseUrl}/auth/login`, {
|
|
35
|
+
method: "POST",
|
|
36
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
37
|
+
body: formData.toString(),
|
|
38
|
+
redirect: "manual",
|
|
39
|
+
});
|
|
40
|
+
if (!response.ok && response.status !== 204 && response.status !== 302) {
|
|
41
|
+
throw new Error(`Login failed (${response.status}). Check your TRACECAT_USERNAME and TRACECAT_PASSWORD in .env`);
|
|
42
|
+
}
|
|
43
|
+
// Extract session cookie from set-cookie header
|
|
44
|
+
const setCookie = response.headers.getSetCookie?.() ?? [];
|
|
45
|
+
for (const cookie of setCookie) {
|
|
46
|
+
const match = cookie.match(/fastapiusersauth=([^;]+)/);
|
|
47
|
+
if (match) {
|
|
48
|
+
this.sessionCookie = match[1];
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// Fallback: try raw header
|
|
53
|
+
const rawSetCookie = response.headers.get("set-cookie") ?? "";
|
|
54
|
+
const match = rawSetCookie.match(/fastapiusersauth=([^;]+)/);
|
|
55
|
+
if (match) {
|
|
56
|
+
this.sessionCookie = match[1];
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
throw new Error("Login succeeded but no session cookie received. " +
|
|
60
|
+
"Check that the Tracecat API is returning a 'fastapiusersauth' cookie.");
|
|
61
|
+
}
|
|
62
|
+
headers() {
|
|
63
|
+
return {
|
|
64
|
+
"Content-Type": "application/json",
|
|
65
|
+
Cookie: `fastapiusersauth=${this.sessionCookie}`,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
async request(method, path, body, queryParams) {
|
|
69
|
+
await this.ensureInitialized();
|
|
70
|
+
// Auto-inject workspace_id on every request (skip auth/workspaces endpoints)
|
|
71
|
+
const params = new URLSearchParams(queryParams);
|
|
72
|
+
if (this.workspaceId && !path.startsWith("/auth") && path !== "/workspaces" && path !== "/ready") {
|
|
73
|
+
if (!params.has("workspace_id")) {
|
|
74
|
+
params.set("workspace_id", this.workspaceId);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
let url = `${this.baseUrl}${path}`;
|
|
78
|
+
const qs = params.toString();
|
|
79
|
+
if (qs) {
|
|
80
|
+
url += `?${qs}`;
|
|
81
|
+
}
|
|
82
|
+
const options = {
|
|
83
|
+
method,
|
|
84
|
+
headers: this.headers(),
|
|
85
|
+
};
|
|
86
|
+
if (body !== undefined) {
|
|
87
|
+
options.body = JSON.stringify(body);
|
|
88
|
+
}
|
|
89
|
+
const response = await fetch(url, options);
|
|
90
|
+
if (!response.ok) {
|
|
91
|
+
const errorText = await response.text();
|
|
92
|
+
throw new Error(`Tracecat API error ${response.status}: ${errorText}`);
|
|
93
|
+
}
|
|
94
|
+
const contentType = response.headers.get("content-type");
|
|
95
|
+
if (contentType?.includes("application/json")) {
|
|
96
|
+
return (await response.json());
|
|
97
|
+
}
|
|
98
|
+
return (await response.text());
|
|
99
|
+
}
|
|
100
|
+
async get(path, queryParams) {
|
|
101
|
+
return this.request("GET", path, undefined, queryParams);
|
|
102
|
+
}
|
|
103
|
+
async post(path, body, queryParams) {
|
|
104
|
+
return this.request("POST", path, body, queryParams);
|
|
105
|
+
}
|
|
106
|
+
async patch(path, body, queryParams) {
|
|
107
|
+
return this.request("PATCH", path, body, queryParams);
|
|
108
|
+
}
|
|
109
|
+
async delete(path, queryParams) {
|
|
110
|
+
return this.request("DELETE", path, undefined, queryParams);
|
|
111
|
+
}
|
|
112
|
+
async initWorkspaceId() {
|
|
113
|
+
if (this.workspaceId)
|
|
114
|
+
return;
|
|
115
|
+
try {
|
|
116
|
+
// /workspaces doesn't need workspace_id
|
|
117
|
+
const response = await fetch(`${this.baseUrl}/workspaces`, {
|
|
118
|
+
headers: {
|
|
119
|
+
Cookie: `fastapiusersauth=${this.sessionCookie}`,
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
if (response.ok) {
|
|
123
|
+
const workspaces = (await response.json());
|
|
124
|
+
if (workspaces.length > 0) {
|
|
125
|
+
this.workspaceId = workspaces[0].id;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
// Workspace ID will remain empty; some endpoints may not require it
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
getWorkspaceId() {
|
|
134
|
+
return this.workspaceId;
|
|
135
|
+
}
|
|
136
|
+
/** Fetch current graph then apply operations with optimistic locking */
|
|
137
|
+
async patchGraph(workflowId, operations) {
|
|
138
|
+
// 1. Get current graph to read base_version (version is at root level)
|
|
139
|
+
const graph = await this.get(`/workflows/${workflowId}/graph`);
|
|
140
|
+
const baseVersion = graph.version;
|
|
141
|
+
// 2. Patch with operations
|
|
142
|
+
return this.patch(`/workflows/${workflowId}/graph`, {
|
|
143
|
+
base_version: baseVersion,
|
|
144
|
+
operations,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { config } from "dotenv";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
import { dirname, resolve } from "path";
|
|
5
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
import { TracecatClient } from "./client.js";
|
|
7
|
+
import { createServer } from "./server.js";
|
|
8
|
+
// Load .env from the mcp_server directory (not cwd)
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
const __dirname = dirname(__filename);
|
|
11
|
+
config({ path: resolve(__dirname, "..", ".env") });
|
|
12
|
+
const apiUrl = process.env.TRACECAT_API_URL ?? "http://localhost/api";
|
|
13
|
+
const username = process.env.TRACECAT_USERNAME ?? "";
|
|
14
|
+
const password = process.env.TRACECAT_PASSWORD ?? "";
|
|
15
|
+
const workspaceId = process.env.TRACECAT_WORKSPACE_ID ?? "";
|
|
16
|
+
if (!username || !password) {
|
|
17
|
+
process.stderr.write("TRACECAT_USERNAME and TRACECAT_PASSWORD environment variables are required\n");
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
const client = new TracecatClient(apiUrl, username, password, workspaceId);
|
|
21
|
+
const server = createServer(client);
|
|
22
|
+
const transport = new StdioServerTransport();
|
|
23
|
+
// Start MCP transport immediately - login happens lazily on first tool call
|
|
24
|
+
server.connect(transport).then(() => {
|
|
25
|
+
process.stderr.write("[tracecat-mcp-community] MCP server ready (login will happen on first request)\n");
|
|
26
|
+
}).catch((error) => {
|
|
27
|
+
process.stderr.write(`[tracecat-mcp-community] Fatal error: ${error}\n`);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
});
|
|
30
|
+
// Graceful shutdown
|
|
31
|
+
process.on("SIGINT", () => process.exit(0));
|
|
32
|
+
process.on("SIGTERM", () => process.exit(0));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/minimal.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
const server = new McpServer({ name: "tracecat", version: "1.0.0" });
|
|
4
|
+
server.tool("ping", "Returns pong", {}, async () => {
|
|
5
|
+
return { content: [{ type: "text", text: "pong" }] };
|
|
6
|
+
});
|
|
7
|
+
const transport = new StdioServerTransport();
|
|
8
|
+
server.connect(transport);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
const server = new McpServer({ name: "tracecat", version: "1.0.0" });
|
|
4
|
+
server.tool("ping", "Returns pong", {}, async () => {
|
|
5
|
+
return { content: [{ type: "text", text: "pong" }] };
|
|
6
|
+
});
|
|
7
|
+
const transport = new StdioServerTransport();
|
|
8
|
+
server.connect(transport);
|
package/dist/server.d.ts
ADDED
package/dist/server.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { registerWorkflowTools } from "./tools/workflows.js";
|
|
3
|
+
import { registerExecutionTools } from "./tools/executions.js";
|
|
4
|
+
import { registerCaseTools } from "./tools/cases.js";
|
|
5
|
+
import { registerActionTools } from "./tools/actions.js";
|
|
6
|
+
import { registerSecretTools } from "./tools/secrets.js";
|
|
7
|
+
import { registerTableTools } from "./tools/tables.js";
|
|
8
|
+
import { registerWebhookTools } from "./tools/webhooks.js";
|
|
9
|
+
import { registerSystemTools } from "./tools/system.js";
|
|
10
|
+
import { registerScheduleTools } from "./tools/schedules.js";
|
|
11
|
+
import { registerGraphTools } from "./tools/graph.js";
|
|
12
|
+
import { registerDocTools } from "./tools/docs.js";
|
|
13
|
+
import { registerTemplateTools } from "./tools/templates.js";
|
|
14
|
+
export function createServer(client) {
|
|
15
|
+
const server = new McpServer({
|
|
16
|
+
name: "tracecat",
|
|
17
|
+
version: "1.0.0",
|
|
18
|
+
});
|
|
19
|
+
registerWorkflowTools(server, client);
|
|
20
|
+
registerExecutionTools(server, client);
|
|
21
|
+
registerCaseTools(server, client);
|
|
22
|
+
registerActionTools(server, client);
|
|
23
|
+
registerSecretTools(server, client);
|
|
24
|
+
registerTableTools(server, client);
|
|
25
|
+
registerWebhookTools(server, client);
|
|
26
|
+
registerScheduleTools(server, client);
|
|
27
|
+
registerSystemTools(server, client);
|
|
28
|
+
registerGraphTools(server, client);
|
|
29
|
+
registerDocTools(server, client);
|
|
30
|
+
registerTemplateTools(server, client);
|
|
31
|
+
return server;
|
|
32
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerActionTools(server, client) {
|
|
3
|
+
server.tool("tracecat_list_actions", "List all actions for a given workflow", {
|
|
4
|
+
workflow_id: z.string().describe("Workflow ID"),
|
|
5
|
+
}, async ({ workflow_id }) => {
|
|
6
|
+
const actions = await client.get(`/actions`, { workflow_id });
|
|
7
|
+
return { content: [{ type: "text", text: JSON.stringify(actions, null, 2) }] };
|
|
8
|
+
});
|
|
9
|
+
server.tool("tracecat_create_action", "Create a new action in a workflow", {
|
|
10
|
+
workflow_id: z.string().describe("Workflow ID"),
|
|
11
|
+
type: z.string().describe("Action type (e.g. core.transform.reshape, core.http.request, core.script.run_python)"),
|
|
12
|
+
title: z.string().describe("Action title"),
|
|
13
|
+
}, async ({ workflow_id, type, title }) => {
|
|
14
|
+
const result = await client.post(`/actions`, { workflow_id, type, title });
|
|
15
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
16
|
+
});
|
|
17
|
+
server.tool("tracecat_get_action", "Get details of a specific action by ID", {
|
|
18
|
+
action_id: z.string().describe("Action ID"),
|
|
19
|
+
workflow_id: z.string().describe("Workflow ID"),
|
|
20
|
+
}, async ({ action_id, workflow_id }) => {
|
|
21
|
+
const action = await client.get(`/actions/${action_id}`, { workflow_id });
|
|
22
|
+
return { content: [{ type: "text", text: JSON.stringify(action, null, 2) }] };
|
|
23
|
+
});
|
|
24
|
+
server.tool("tracecat_update_action", "Update an existing action (title, description, inputs, control_flow). Note: inputs must be a YAML string, not a JSON object.", {
|
|
25
|
+
action_id: z.string().describe("Action ID"),
|
|
26
|
+
workflow_id: z.string().describe("Workflow ID"),
|
|
27
|
+
title: z.string().optional().describe("New title"),
|
|
28
|
+
description: z.string().optional().describe("New description"),
|
|
29
|
+
inputs: z.string().optional().describe("Action inputs as a YAML string (e.g. 'value: hello\\nurl: https://...')"),
|
|
30
|
+
control_flow: z.object({
|
|
31
|
+
run_if: z.string().nullable().optional().describe("Conditional expression"),
|
|
32
|
+
for_each: z.string().nullable().optional().describe("Loop expression"),
|
|
33
|
+
join_strategy: z.string().optional().describe("'all' or 'any'"),
|
|
34
|
+
retry_policy: z.object({
|
|
35
|
+
max_attempts: z.number().optional(),
|
|
36
|
+
timeout: z.number().optional(),
|
|
37
|
+
retry_until: z.string().nullable().optional(),
|
|
38
|
+
}).optional(),
|
|
39
|
+
start_delay: z.number().optional().describe("Delay in seconds before execution"),
|
|
40
|
+
}).optional().describe("Control flow settings"),
|
|
41
|
+
}, async ({ action_id, workflow_id, ...updates }) => {
|
|
42
|
+
const body = Object.fromEntries(Object.entries(updates).filter(([, v]) => v !== undefined));
|
|
43
|
+
// Update uses POST, not PATCH
|
|
44
|
+
const result = await client.post(`/actions/${action_id}`, body, { workflow_id });
|
|
45
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
46
|
+
});
|
|
47
|
+
server.tool("tracecat_delete_action", "Delete an action from a workflow", {
|
|
48
|
+
action_id: z.string().describe("Action ID"),
|
|
49
|
+
workflow_id: z.string().describe("Workflow ID"),
|
|
50
|
+
}, async ({ action_id, workflow_id }) => {
|
|
51
|
+
const result = await client.delete(`/actions/${action_id}`, { workflow_id });
|
|
52
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
53
|
+
});
|
|
54
|
+
}
|