#
tokens: 18515/50000 15/16 files (page 1/2)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 1 of 2. Use http://codebase.md/spathodea-network/opencti-mcp?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .env.example
├── .gitignore
├── Dockerfile
├── LICENSE
├── package.json
├── README.md
├── README.zh-TW.md
├── smithery.yaml
├── src
│   ├── index.ts
│   ├── opencti.graphql
│   └── queries
│       ├── metadata.ts
│       ├── references.ts
│       ├── relationships.ts
│       ├── reports.ts
│       ├── stix_objects.ts
│       ├── system.ts
│       └── users.ts
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------

```
1 | # OpenCTI Configuration
2 | OPENCTI_URL=http://localhost:8080
3 | OPENCTI_TOKEN=your-api-token-here
4 | 
```

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
 1 | # Dependencies
 2 | node_modules/
 3 | package-lock.json
 4 | 
 5 | # Build output
 6 | build/
 7 | dist/
 8 | 
 9 | # Environment files
10 | .env
11 | .env.local
12 | .env.*.local
13 | 
14 | # IDE files
15 | .vscode/
16 | .idea/
17 | *.iml
18 | 
19 | # Logs
20 | logs/
21 | *.log
22 | npm-debug.log*
23 | 
24 | # System files
25 | .DS_Store
26 | Thumbs.db
27 | 
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
  1 | # OpenCTI MCP Server
  2 | 
  3 | [![smithery badge](https://smithery.ai/badge/opencti-server)](https://smithery.ai/server/opencti-server)
  4 | [Traditional Chinese (繁體中文)](README.zh-TW.md)
  5 | 
  6 | <a href="https://glama.ai/mcp/servers/ml61kiz1gm"><img width="380" height="200" src="https://glama.ai/mcp/servers/ml61kiz1gm/badge" alt="OpenCTI Server MCP server" /></a>
  7 | 
  8 | ## Overview
  9 | OpenCTI MCP Server is a Model Context Protocol (MCP) server that provides seamless integration with OpenCTI (Open Cyber Threat Intelligence) platform. It enables querying and retrieving threat intelligence data through a standardized interface.
 10 | 
 11 | ## Features
 12 | - Fetch and search threat intelligence data
 13 |   - Get latest reports and search by ID
 14 |   - Search for malware information
 15 |   - Query indicators of compromise
 16 |   - Search for threat actors
 17 | - User and group management
 18 |   - List all users and groups
 19 |   - Get user details by ID
 20 | - STIX object operations
 21 |   - List attack patterns
 22 |   - Get campaign information by name
 23 | - System management
 24 |   - List connectors
 25 |   - View status templates
 26 | - File operations
 27 |   - List all files
 28 |   - Get file details by ID
 29 | - Reference data access
 30 |   - List marking definitions
 31 |   - View available labels
 32 | - Customizable query limits
 33 | - Full GraphQL query support
 34 | 
 35 | ## Prerequisites
 36 | - Node.js 16 or higher
 37 | - Access to an OpenCTI instance
 38 | - OpenCTI API token
 39 | 
 40 | ## Installation
 41 | 
 42 | ### Installing via Smithery
 43 | 
 44 | To install OpenCTI Server for Claude Desktop automatically via [Smithery](https://smithery.ai/server/opencti-server):
 45 | 
 46 | ```bash
 47 | npx -y @smithery/cli install opencti-server --client claude
 48 | ```
 49 | 
 50 | ### Manual Installation
 51 | ```bash
 52 | # Clone the repository
 53 | git clone https://github.com/yourusername/opencti-mcp-server.git
 54 | 
 55 | # Install dependencies
 56 | cd opencti-mcp-server
 57 | npm install
 58 | 
 59 | # Build the project
 60 | npm run build
 61 | ```
 62 | 
 63 | ## Configuration
 64 | 
 65 | ### Environment Variables
 66 | Copy `.env.example` to `.env` and update with your OpenCTI credentials:
 67 | ```bash
 68 | cp .env.example .env
 69 | ```
 70 | 
 71 | Required environment variables:
 72 | - `OPENCTI_URL`: Your OpenCTI instance URL
 73 | - `OPENCTI_TOKEN`: Your OpenCTI API token
 74 | 
 75 | ### MCP Settings
 76 | Create a configuration file in your MCP settings location:
 77 | ```json
 78 | {
 79 |   "mcpServers": {
 80 |     "opencti": {
 81 |       "command": "node",
 82 |       "args": ["path/to/opencti-server/build/index.js"],
 83 |       "env": {
 84 |         "OPENCTI_URL": "${OPENCTI_URL}",  // Will be loaded from .env
 85 |         "OPENCTI_TOKEN": "${OPENCTI_TOKEN}"  // Will be loaded from .env
 86 |       }
 87 |     }
 88 |   }
 89 | }
 90 | ```
 91 | 
 92 | ### Security Notes
 93 | - Never commit `.env` file or API tokens to version control
 94 | - Keep your OpenCTI credentials secure
 95 | - The `.gitignore` file is configured to exclude sensitive files
 96 | 
 97 | ## Available Tools
 98 | 
 99 | ## Available Tools
100 | 
101 | ### Reports
102 | #### get_latest_reports
103 | Retrieves the most recent threat intelligence reports.
104 | ```typescript
105 | {
106 |   "name": "get_latest_reports",
107 |   "arguments": {
108 |     "first": 10  // Optional, defaults to 10
109 |   }
110 | }
111 | ```
112 | 
113 | #### get_report_by_id
114 | Retrieves a specific report by its ID.
115 | ```typescript
116 | {
117 |   "name": "get_report_by_id",
118 |   "arguments": {
119 |     "id": "report-uuid"  // Required
120 |   }
121 | }
122 | ```
123 | 
124 | ### Search Operations
125 | #### search_malware
126 | Searches for malware information in the OpenCTI database.
127 | ```typescript
128 | {
129 |   "name": "search_malware",
130 |   "arguments": {
131 |     "query": "ransomware",
132 |     "first": 10  // Optional, defaults to 10
133 |   }
134 | }
135 | ```
136 | 
137 | #### search_indicators
138 | Searches for indicators of compromise.
139 | ```typescript
140 | {
141 |   "name": "search_indicators",
142 |   "arguments": {
143 |     "query": "domain",
144 |     "first": 10  // Optional, defaults to 10
145 |   }
146 | }
147 | ```
148 | 
149 | #### search_threat_actors
150 | Searches for threat actor information.
151 | ```typescript
152 | {
153 |   "name": "search_threat_actors",
154 |   "arguments": {
155 |     "query": "APT",
156 |     "first": 10  // Optional, defaults to 10
157 |   }
158 | }
159 | ```
160 | 
161 | ### User Management
162 | #### get_user_by_id
163 | Retrieves user information by ID.
164 | ```typescript
165 | {
166 |   "name": "get_user_by_id",
167 |   "arguments": {
168 |     "id": "user-uuid"  // Required
169 |   }
170 | }
171 | ```
172 | 
173 | #### list_users
174 | Lists all users in the system.
175 | ```typescript
176 | {
177 |   "name": "list_users",
178 |   "arguments": {}
179 | }
180 | ```
181 | 
182 | #### list_groups
183 | Lists all groups with their members.
184 | ```typescript
185 | {
186 |   "name": "list_groups",
187 |   "arguments": {
188 |     "first": 10  // Optional, defaults to 10
189 |   }
190 | }
191 | ```
192 | 
193 | ### STIX Objects
194 | #### list_attack_patterns
195 | Lists all attack patterns in the system.
196 | ```typescript
197 | {
198 |   "name": "list_attack_patterns",
199 |   "arguments": {
200 |     "first": 10  // Optional, defaults to 10
201 |   }
202 | }
203 | ```
204 | 
205 | #### get_campaign_by_name
206 | Retrieves campaign information by name.
207 | ```typescript
208 | {
209 |   "name": "get_campaign_by_name",
210 |   "arguments": {
211 |     "name": "campaign-name"  // Required
212 |   }
213 | }
214 | ```
215 | 
216 | ### System Management
217 | #### list_connectors
218 | Lists all system connectors.
219 | ```typescript
220 | {
221 |   "name": "list_connectors",
222 |   "arguments": {}
223 | }
224 | ```
225 | 
226 | #### list_status_templates
227 | Lists all status templates.
228 | ```typescript
229 | {
230 |   "name": "list_status_templates",
231 |   "arguments": {}
232 | }
233 | ```
234 | 
235 | ### File Operations
236 | #### get_file_by_id
237 | Retrieves file information by ID.
238 | ```typescript
239 | {
240 |   "name": "get_file_by_id",
241 |   "arguments": {
242 |     "id": "file-uuid"  // Required
243 |   }
244 | }
245 | ```
246 | 
247 | #### list_files
248 | Lists all files in the system.
249 | ```typescript
250 | {
251 |   "name": "list_files",
252 |   "arguments": {}
253 | }
254 | ```
255 | 
256 | ### Reference Data
257 | #### list_marking_definitions
258 | Lists all marking definitions.
259 | ```typescript
260 | {
261 |   "name": "list_marking_definitions",
262 |   "arguments": {}
263 | }
264 | ```
265 | 
266 | #### list_labels
267 | Lists all available labels.
268 | ```typescript
269 | {
270 |   "name": "list_labels",
271 |   "arguments": {}
272 | }
273 | ```
274 | 
275 | ## Contributing
276 | Contributions are welcome! Please feel free to submit pull requests.
277 | 
278 | ## License
279 | MIT License
280 | 
```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "ES2022",
 4 |     "module": "Node16",
 5 |     "moduleResolution": "Node16",
 6 |     "outDir": "./build",
 7 |     "rootDir": "./src",
 8 |     "strict": true,
 9 |     "esModuleInterop": true,
10 |     "skipLibCheck": true,
11 |     "forceConsistentCasingInFileNames": true
12 |   },
13 |   "include": ["src/**/*"],
14 |   "exclude": ["node_modules"]
15 | }
16 | 
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "opencti-server",
 3 |   "version": "0.1.0",
 4 |   "description": "A Model Context Protocol server",
 5 |   "private": true,
 6 |   "type": "module",
 7 |   "bin": {
 8 |     "opencti-server": "./build/index.js"
 9 |   },
10 |   "files": [
11 |     "build"
12 |   ],
13 |   "scripts": {
14 |     "build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
15 |     "prepare": "npm run build",
16 |     "watch": "tsc --watch",
17 |     "inspector": "npx @modelcontextprotocol/inspector build/index.js"
18 |   },
19 |   "dependencies": {
20 |     "@modelcontextprotocol/sdk": "0.6.0",
21 |     "axios": "^1.7.9"
22 |   },
23 |   "devDependencies": {
24 |     "@types/node": "^20.11.24",
25 |     "typescript": "^5.3.3"
26 |   }
27 | }
28 | 
```

--------------------------------------------------------------------------------
/smithery.yaml:
--------------------------------------------------------------------------------

```yaml
 1 | # Smithery configuration file: https://smithery.ai/docs/config#smitheryyaml
 2 | 
 3 | startCommand:
 4 |   type: stdio
 5 |   configSchema:
 6 |     # JSON Schema defining the configuration options for the MCP.
 7 |     type: object
 8 |     required:
 9 |       - openctiUrl
10 |       - openctiToken
11 |     properties:
12 |       openctiUrl:
13 |         type: string
14 |         description: The URL of the OpenCTI instance.
15 |       openctiToken:
16 |         type: string
17 |         description: The API token for the OpenCTI instance.
18 |   commandFunction:
19 |     # A function that produces the CLI command to start the MCP on stdio.
20 |     |-
21 |     (config) => ({command: 'node', args: ['build/index.js'], env: {OPENCTI_URL: config.openctiUrl, OPENCTI_TOKEN: config.openctiToken}})
22 | 
```

--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------

```dockerfile
 1 | # Generated by https://smithery.ai. See: https://smithery.ai/docs/config#dockerfile
 2 | # Use a Node.js image with the appropriate version
 3 | FROM node:16-alpine AS builder
 4 | 
 5 | # Set working directory
 6 | WORKDIR /app
 7 | 
 8 | # Copy package.json and package-lock.json for dependency installation
 9 | COPY package.json package.json
10 | 
11 | # Install dependencies
12 | RUN npm install --ignore-scripts
13 | 
14 | # Copy the rest of the application source code
15 | COPY . .
16 | 
17 | # Build the TypeScript project
18 | RUN npm run build
19 | 
20 | # Prepare the runtime environment
21 | FROM node:16-alpine AS release
22 | 
23 | # Set working directory
24 | WORKDIR /app
25 | 
26 | # Copy built files and necessary configuration
27 | COPY --from=builder /app/build /app/build
28 | COPY --from=builder /app/package.json /app/package.json
29 | 
30 | # Set environment variables
31 | ENV OPENCTI_URL=https://your-opencti-url
32 | ENV OPENCTI_TOKEN=your-opencti-token
33 | 
34 | # Run the server
35 | ENTRYPOINT ["node", "build/index.js"]
36 | 
```

--------------------------------------------------------------------------------
/src/queries/references.ts:
--------------------------------------------------------------------------------

```typescript
 1 | export const ALL_MARKING_DEFINITIONS_QUERY = `
 2 | query AllMarkingDefinitions {
 3 |   markingDefinitions {
 4 |     edges {
 5 |       node {
 6 |         id
 7 |         standard_id
 8 |         entity_type
 9 |         definition_type
10 |         definition
11 |         x_opencti_order
12 |         x_opencti_color
13 |       }
14 |     }
15 |   }
16 | }
17 | `;
18 | 
19 | export const ALL_LABELS_QUERY = `
20 | query AllLabels {
21 |   labels {
22 |     edges {
23 |       node {
24 |         id
25 |         standard_id
26 |         entity_type
27 |         value
28 |         color
29 |       }
30 |     }
31 |   }
32 | }
33 | `;
34 | 
35 | export const ALL_EXTERNAL_REFERENCES_QUERY = `
36 | query AllExternalReferences {
37 |   externalReferences {
38 |     edges {
39 |       node {
40 |         id
41 |         standard_id
42 |         entity_type
43 |         source_name
44 |         description
45 |         url
46 |         hash
47 |         external_id
48 |       }
49 |     }
50 |   }
51 | }
52 | `;
53 | 
54 | export const ALL_KILL_CHAIN_PHASES_QUERY = `
55 | query AllKillChainPhases {
56 |   killChainPhases {
57 |     edges {
58 |       node {
59 |         id
60 |         standard_id
61 |         entity_type
62 |         kill_chain_name
63 |         phase_name
64 |         x_opencti_order
65 |       }
66 |     }
67 |   }
68 | }
69 | `;
70 | 
```

--------------------------------------------------------------------------------
/src/queries/users.ts:
--------------------------------------------------------------------------------

```typescript
  1 | export const USER_BY_ID_QUERY = `
  2 | query UserById($id: String!) {
  3 |   user(id: $id) {
  4 |     id
  5 |     standard_id
  6 |     entity_type
  7 |     parent_types
  8 |     user_email
  9 |     name
 10 |     firstname
 11 |     lastname
 12 |     groups {
 13 |       edges {
 14 |         node {
 15 |           id
 16 |           name
 17 |         }
 18 |       }
 19 |     }
 20 |   }
 21 | }
 22 | `;
 23 | 
 24 | export const ALL_USERS_QUERY = `
 25 | query AllUsers {
 26 |   users {
 27 |     edges {
 28 |       node {
 29 |         id
 30 |         standard_id
 31 |         entity_type
 32 |         user_email
 33 |         name
 34 |         firstname
 35 |         lastname
 36 |         external
 37 |         created_at
 38 |         updated_at
 39 |       }
 40 |     }
 41 |   }
 42 | }
 43 | `;
 44 | 
 45 | export const ALL_GROUPS_QUERY = `
 46 | query AllGroups($first: Int, $after: ID) {
 47 |   groups(first: $first, after: $after) {
 48 |     pageInfo {
 49 |       hasNextPage
 50 |       endCursor
 51 |     }
 52 |     edges {
 53 |       node {
 54 |         id
 55 |         standard_id
 56 |         entity_type
 57 |         parent_types
 58 |         name
 59 |         description
 60 |         members(first: 5) {
 61 |           edges {
 62 |             node {
 63 |               id
 64 |               name
 65 |               user_email
 66 |             }
 67 |           }
 68 |         }
 69 |       }
 70 |     }
 71 |   }
 72 | }
 73 | `;
 74 | 
 75 | export const ALL_ROLES_QUERY = `
 76 | query AllRoles {
 77 |   roles {
 78 |     edges {
 79 |       node {
 80 |         id
 81 |         standard_id
 82 |         entity_type
 83 |         name
 84 |         description
 85 |         created_at
 86 |         updated_at
 87 |       }
 88 |     }
 89 |   }
 90 | }
 91 | `;
 92 | 
 93 | export const ALL_CAPABILITIES_QUERY = `
 94 | query AllCapabilities {
 95 |   capabilities {
 96 |     edges {
 97 |       node {
 98 |         id
 99 |         standard_id
100 |         entity_type
101 |         name
102 |         description
103 |         attribute_order
104 |         created_at
105 |         updated_at
106 |       }
107 |     }
108 |   }
109 | }
110 | `;
111 | 
```

--------------------------------------------------------------------------------
/src/queries/metadata.ts:
--------------------------------------------------------------------------------

```typescript
  1 | export const FILE_BY_ID_QUERY = `
  2 | query FileById($id: String!) {
  3 |   file(id: $id) {
  4 |     id
  5 |     name
  6 |     size
  7 |     lastModified
  8 |     uploadStatus
  9 |   }
 10 | }
 11 | `;
 12 | 
 13 | export const ALL_FILES_QUERY = `
 14 | query AllFiles {
 15 |   importFiles(first: 100) {
 16 |     edges {
 17 |       node {
 18 |         id
 19 |         name
 20 |         size
 21 |         uploadStatus
 22 |         lastModified
 23 |         metaData {
 24 |           mimetype
 25 |           version
 26 |         }
 27 |       }
 28 |     }
 29 |   }
 30 | }
 31 | `;
 32 | 
 33 | export const ALL_INDEXED_FILES_QUERY = `
 34 | query AllIndexedFiles {
 35 |   indexedFiles {
 36 |     edges {
 37 |       node {
 38 |         id
 39 |         name
 40 |         file_id
 41 |         uploaded_at
 42 |         entity {
 43 |           id
 44 |           entity_type
 45 |           parent_types
 46 |           standard_id
 47 |         }
 48 |         searchOccurrences
 49 |       }
 50 |     }
 51 |   }
 52 | }
 53 | `;
 54 | 
 55 | export const ALL_LOGS_QUERY = `
 56 | query AllLogs {
 57 |   logs {
 58 |     edges {
 59 |       node {
 60 |         id
 61 |         entity_type
 62 |         event_type
 63 |         event_scope
 64 |         event_status
 65 |         timestamp
 66 |         user_id
 67 |         user {
 68 |           id
 69 |           name
 70 |           entity_type
 71 |         }
 72 |         context_uri
 73 |         context_data {
 74 |           entity_id
 75 |           entity_name
 76 |           entity_type
 77 |           from_id
 78 |           to_id
 79 |           message
 80 |           commit
 81 |           external_references {
 82 |             id
 83 |             source_name
 84 |             description
 85 |             url
 86 |             hash
 87 |             external_id
 88 |           }
 89 |         }
 90 |       }
 91 |     }
 92 |   }
 93 | }
 94 | `;
 95 | 
 96 | export const ALL_AUDITS_QUERY = `
 97 | query AllAudits {
 98 |   audits {
 99 |     edges {
100 |       node {
101 |         id
102 |         entity_type
103 |         event_type
104 |         event_scope
105 |         event_status
106 |         timestamp
107 |         user_id
108 |         user {
109 |           id
110 |           name
111 |           entity_type
112 |         }
113 |         context_uri
114 |         context_data {
115 |           entity_id
116 |           entity_name
117 |           entity_type
118 |           from_id
119 |           to_id
120 |           message
121 |           commit
122 |           external_references {
123 |             id
124 |             source_name
125 |             description
126 |             url
127 |             hash
128 |             external_id
129 |           }
130 |         }
131 |       }
132 |     }
133 |   }
134 | }
135 | `;
136 | 
137 | export const ALL_ATTRIBUTES_QUERY = `
138 | query AllAttributes {
139 |   runtimeAttributes {
140 |     edges {
141 |       node {
142 |         id
143 |         key
144 |         value
145 |       }
146 |     }
147 |   }
148 | }
149 | `;
150 | 
151 | export const ALL_SCHEMA_ATTRIBUTE_NAMES_QUERY = `
152 | query AllSchemaAttributeNames {
153 |   schemaAttributeNames(elementType: ["Report", "Note"]) {
154 |     edges {
155 |       node {
156 |         id
157 |         key
158 |         value
159 |       }
160 |     }
161 |   }
162 | }
163 | `;
164 | 
165 | export const ALL_FILTER_KEYS_SCHEMA_QUERY = `
166 | query AllFilterKeysSchema {
167 |   filterKeysSchema {
168 |     entity_type
169 |     filters_schema {
170 |       filterKey
171 |       filterDefinition {
172 |         filterKey
173 |         label
174 |         type
175 |         multiple
176 |         subEntityTypes
177 |         elementsForFilterValuesSearch
178 |         subFilters {
179 |           filterKey
180 |           label
181 |           type
182 |           multiple
183 |           subEntityTypes
184 |           elementsForFilterValuesSearch
185 |         }
186 |       }
187 |     }
188 |   }
189 | }
190 | `;
191 | 
```

--------------------------------------------------------------------------------
/src/queries/relationships.ts:
--------------------------------------------------------------------------------

```typescript
  1 | export const ALL_STIX_CORE_RELATIONSHIPS_QUERY = `
  2 | query AllStixCoreRelationships($first: Int, $after: ID) {
  3 |   stixCoreRelationships(first: $first, after: $after) {
  4 |     pageInfo {
  5 |       hasNextPage
  6 |       endCursor
  7 |     }
  8 |     edges {
  9 |       node {
 10 |         id
 11 |         standard_id
 12 |         entity_type
 13 |         parent_types
 14 |         relationship_type
 15 |         confidence
 16 |         start_time
 17 |         stop_time
 18 |         from {
 19 |           ... on StixDomainObject {
 20 |             id
 21 |             entity_type
 22 |             name
 23 |           }
 24 |           ... on StixCyberObservable {
 25 |             id
 26 |             entity_type
 27 |             observable_value
 28 |           }
 29 |         }
 30 |         to {
 31 |           ... on StixDomainObject {
 32 |             id
 33 |             entity_type
 34 |             name
 35 |           }
 36 |           ... on StixCyberObservable {
 37 |             id
 38 |             entity_type
 39 |             observable_value
 40 |           }
 41 |         }
 42 |       }
 43 |     }
 44 |   }
 45 | }
 46 | `;
 47 | 
 48 | export const ALL_STIX_SIGHTING_RELATIONSHIPS_QUERY = `
 49 | query AllStixSightingRelationships($first: Int, $after: ID) {
 50 |   stixSightingRelationships(first: $first, after: $after) {
 51 |     pageInfo {
 52 |       hasNextPage
 53 |       endCursor
 54 |     }
 55 |     edges {
 56 |       node {
 57 |         id
 58 |         standard_id
 59 |         entity_type
 60 |         parent_types
 61 |         relationship_type
 62 |         confidence
 63 |         first_seen
 64 |         last_seen
 65 |         from {
 66 |           ... on StixDomainObject {
 67 |             id
 68 |             entity_type
 69 |             name
 70 |           }
 71 |           ... on StixCyberObservable {
 72 |             id
 73 |             entity_type
 74 |             observable_value
 75 |           }
 76 |         }
 77 |         to {
 78 |           ... on StixDomainObject {
 79 |             id
 80 |             entity_type
 81 |             name
 82 |           }
 83 |           ... on StixCyberObservable {
 84 |             id
 85 |             entity_type
 86 |             observable_value
 87 |           }
 88 |         }
 89 |       }
 90 |     }
 91 |   }
 92 | }
 93 | `;
 94 | 
 95 | export const ALL_STIX_REF_RELATIONSHIPS_QUERY = `
 96 | query AllStixRefRelationships($first: Int, $after: ID) {
 97 |   stixRefRelationships(first: $first, after: $after) {
 98 |     pageInfo {
 99 |       hasNextPage
100 |       endCursor
101 |     }
102 |     edges {
103 |       node {
104 |         id
105 |         standard_id
106 |         entity_type
107 |         parent_types
108 |         relationship_type
109 |         confidence
110 |         from {
111 |           ... on StixDomainObject {
112 |             id
113 |             entity_type
114 |             name
115 |           }
116 |           ... on StixCyberObservable {
117 |             id
118 |             entity_type
119 |             observable_value
120 |           }
121 |         }
122 |         to {
123 |           ... on StixDomainObject {
124 |             id
125 |             entity_type
126 |             name
127 |           }
128 |           ... on StixCyberObservable {
129 |             id
130 |             entity_type
131 |             observable_value
132 |           }
133 |         }
134 |       }
135 |     }
136 |   }
137 | }
138 | `;
139 | 
140 | export const ALL_STIX_RELATIONSHIPS_QUERY = `
141 | query AllStixRelationships {
142 |   stixRelationships {
143 |     edges {
144 |       node {
145 |         id
146 |         standard_id
147 |         entity_type
148 |         parent_types
149 |         relationship_type
150 |         confidence
151 |         created_at
152 |         updated_at
153 |         from {
154 |           ... on StixDomainObject {
155 |             id
156 |             entity_type
157 |             name
158 |           }
159 |           ... on StixCyberObservable {
160 |             id
161 |             entity_type
162 |             observable_value
163 |           }
164 |         }
165 |         to {
166 |           ... on StixDomainObject {
167 |             id
168 |             entity_type
169 |             name
170 |           }
171 |           ... on StixCyberObservable {
172 |             id
173 |             entity_type
174 |             observable_value
175 |           }
176 |         }
177 |         objectMarking {
178 |           id
179 |           definition
180 |           x_opencti_order
181 |           x_opencti_color
182 |         }
183 |         createdBy {
184 |           id
185 |           name
186 |           entity_type
187 |         }
188 |       }
189 |     }
190 |   }
191 | }
192 | `;
193 | 
```

--------------------------------------------------------------------------------
/src/queries/reports.ts:
--------------------------------------------------------------------------------

```typescript
  1 | export const LATEST_REPORTS_QUERY = `
  2 | query LatestReport($first: Int) {
  3 |   reports(
  4 |     first: $first,
  5 |     orderBy: created,
  6 |     orderMode: desc
  7 |   ) {
  8 |     edges {
  9 |       node {
 10 |         # Basic fields
 11 |         id
 12 |         standard_id
 13 |         entity_type
 14 |         parent_types
 15 |         
 16 |         # Report specific fields
 17 |         name
 18 |         description
 19 |         content
 20 |         content_mapping
 21 |         report_types
 22 |         published
 23 |         confidence
 24 |         createdBy {
 25 |           id
 26 |           name
 27 |           entity_type
 28 |         }
 29 |         objectMarking {
 30 |           id
 31 |           definition
 32 |           x_opencti_order
 33 |           x_opencti_color
 34 |         }
 35 |         objectLabel {
 36 |           id
 37 |           value
 38 |           color
 39 |         }
 40 |         externalReferences {
 41 |           edges {
 42 |             node {
 43 |               id
 44 |               source_name
 45 |               description
 46 |               url
 47 |               hash
 48 |               external_id
 49 |             }
 50 |           }
 51 |         }
 52 |         
 53 |         # Relationships and objects
 54 |         objects(first: 500) {
 55 |           edges {
 56 |             node {
 57 |               ... on StixDomainObject {
 58 |                 id
 59 |                 entity_type
 60 |                 parent_types
 61 |           created
 62 |                 updated_at
 63 |                 standard_id
 64 |                 created
 65 |                 revoked
 66 |                 confidence
 67 |                 lang
 68 |                 status {
 69 |                   id
 70 |                   template {
 71 |                     name
 72 |                     color
 73 |                   }
 74 |                 }
 75 |               }
 76 |               ... on StixCyberObservable {
 77 |                 id
 78 |                 entity_type
 79 |                 parent_types
 80 |                 observable_value
 81 |                 x_opencti_description
 82 |                 x_opencti_score
 83 |               }
 84 |               ... on StixCoreRelationship {
 85 |                 id
 86 |                 entity_type
 87 |                 parent_types
 88 |                 relationship_type
 89 |                 description
 90 |                 start_time
 91 |                 stop_time
 92 |                 from {
 93 |                   ... on StixDomainObject {
 94 |                     id
 95 |                     entity_type
 96 |                     parent_types
 97 |                     created_at
 98 |                     standard_id
 99 |                   }
100 |                 }
101 |                 to {
102 |                   ... on StixDomainObject {
103 |                     id
104 |                     entity_type
105 |                     parent_types
106 |                     created_at
107 |                     standard_id
108 |                   }
109 |                 }
110 |               }
111 |             }
112 |           }
113 |         }
114 |         
115 |         # Additional metadata
116 |         created
117 |         modified
118 |         created_at
119 |         updated_at
120 |         x_opencti_stix_ids
121 |         status {
122 |           id
123 |           template {
124 |             name
125 |             color
126 |           }
127 |         }
128 |         workflowEnabled
129 |         
130 |         # Container specific fields
131 |         containersNumber {
132 |           total
133 |           count
134 |         }
135 |         containers {
136 |           edges {
137 |             node {
138 |               id
139 |               entity_type
140 |               parent_types
141 |               created_at
142 |               standard_id
143 |             }
144 |           }
145 |         }
146 |       }
147 |     }
148 |   }
149 | }
150 | `;
151 | 
152 | export const SEARCH_MALWARE_QUERY = `
153 | query Malware($search: String, $first: Int) {
154 |   stixCoreObjects(
155 |     search: $search,
156 |     first: $first,
157 |     types: ["Malware"]
158 |   ) {
159 |     edges {
160 |       node {
161 |         ... on Malware {
162 |           id
163 |           name
164 |           description
165 |           created
166 |           modified
167 |           malware_types
168 |           is_family
169 |           first_seen
170 |           last_seen
171 |         }
172 |       }
173 |     }
174 |   }
175 | }
176 | `;
177 | 
178 | export const SEARCH_INDICATORS_QUERY = `
179 | query Indicators($search: String, $first: Int) {
180 |   stixCoreObjects(
181 |     search: $search,
182 |     first: $first,
183 |     types: ["Indicator"]
184 |   ) {
185 |     edges {
186 |       node {
187 |         ... on Indicator {
188 |           id
189 |           name
190 |           description
191 |           created_at
192 |           pattern
193 |           valid_from
194 |           valid_until
195 |           x_opencti_score
196 |         }
197 |       }
198 |     }
199 |   }
200 | }
201 | `;
202 | 
203 | export const SEARCH_THREAT_ACTORS_QUERY = `
204 | query ThreatActors($search: String, $first: Int) {
205 |   stixCoreObjects(
206 |     search: $search,
207 |     first: $first,
208 |     types: ["ThreatActorGroup"]
209 |   ) {
210 |     edges {
211 |       node {
212 |         ... on ThreatActorGroup {
213 |           id
214 |           name
215 |           description
216 |           created
217 |           modified
218 |           threat_actor_types
219 |           first_seen
220 |           last_seen
221 |           sophistication
222 |           resource_level
223 |           roles
224 |           goals
225 |         }
226 |       }
227 |     }
228 |   }
229 | }
230 | `;
231 | 
```

--------------------------------------------------------------------------------
/src/queries/system.ts:
--------------------------------------------------------------------------------

```typescript
  1 | export const ALL_CONNECTORS_QUERY = `
  2 | query AllConnectors {
  3 |   connectors {
  4 |     id
  5 |     name
  6 |     active
  7 |     auto
  8 |     only_contextual
  9 |     playbook_compatible
 10 |     connector_type
 11 |     connector_scope
 12 |     connector_state
 13 |     connector_schema
 14 |     connector_schema_ui
 15 |     connector_state_reset
 16 |     connector_user_id
 17 |     updated_at
 18 |     created_at
 19 |     config {
 20 |       connection {
 21 |         host
 22 |         vhost
 23 |         use_ssl
 24 |         port
 25 |         user
 26 |         pass
 27 |       }
 28 |       listen
 29 |       listen_routing
 30 |       listen_exchange
 31 |       push
 32 |       push_routing
 33 |       push_exchange
 34 |     }
 35 |     works {
 36 |       id
 37 |       name
 38 |       status
 39 |     }
 40 |   }
 41 | }
 42 | `;
 43 | 
 44 | export const ALL_STATUS_TEMPLATES_QUERY = `
 45 | query AllStatusTemplates {
 46 |   statusTemplates {
 47 |     edges {
 48 |       node {
 49 |         id
 50 |         name
 51 |         color
 52 |         editContext {
 53 |           name
 54 |           focusOn
 55 |         }
 56 |         usages
 57 |       }
 58 |     }
 59 |   }
 60 | }
 61 | `;
 62 | 
 63 | export const ALL_STATUSES_QUERY = `
 64 | query AllStatuses {
 65 |   statuses {
 66 |     edges {
 67 |       node {
 68 |         id
 69 |         template_id
 70 |         template {
 71 |           id
 72 |           name
 73 |           color
 74 |         }
 75 |         type
 76 |         order
 77 |         disabled
 78 |       }
 79 |     }
 80 |   }
 81 | }
 82 | `;
 83 | 
 84 | export const ALL_SUB_TYPES_QUERY = `
 85 | query AllSubTypes {
 86 |   subTypes {
 87 |     edges {
 88 |       node {
 89 |         id
 90 |         label
 91 |         statuses {
 92 |           id
 93 |           template {
 94 |             id
 95 |             name
 96 |             color
 97 |           }
 98 |           type
 99 |           order
100 |           disabled
101 |         }
102 |         workflowEnabled
103 |         settings {
104 |           id
105 |           entity_type
106 |           parent_types
107 |           standard_id
108 |         }
109 |       }
110 |     }
111 |   }
112 | }
113 | `;
114 | 
115 | export const ALL_RETENTION_RULES_QUERY = `
116 | query AllRetentionRules {
117 |   retentionRules {
118 |     edges {
119 |       node {
120 |         id
121 |         standard_id
122 |         name
123 |         filters
124 |         max_retention
125 |         retention_unit
126 |         last_execution_date
127 |         last_deleted_count
128 |         remaining_count
129 |         scope
130 |       }
131 |     }
132 |   }
133 | }
134 | `;
135 | 
136 | export const ALL_BACKGROUND_TASKS_QUERY = `
137 | query AllBackgroundTasks {
138 |   backgroundTasks {
139 |     edges {
140 |       node {
141 |         id
142 |         type
143 |         initiator {
144 |           id
145 |           name
146 |           entity_type
147 |         }
148 |         actions {
149 |           type
150 |           context {
151 |             field
152 |             type
153 |             values
154 |           }
155 |         }
156 |         created_at
157 |         last_execution_date
158 |         completed
159 |         task_expected_number
160 |         task_processed_number
161 |         errors {
162 |           id
163 |           timestamp
164 |           message
165 |         }
166 |       }
167 |     }
168 |   }
169 | }
170 | `;
171 | 
172 | export const ALL_FEEDS_QUERY = `
173 | query AllFeeds {
174 |   feeds {
175 |     edges {
176 |       node {
177 |         id
178 |         standard_id
179 |         name
180 |         description
181 |         filters
182 |         separator
183 |         rolling_time
184 |         feed_date_attribute
185 |         include_header
186 |         feed_types
187 |         feed_attributes {
188 |           attribute
189 |           mappings {
190 |             type
191 |             attribute
192 |           }
193 |         }
194 |         feed_public
195 |         authorized_members {
196 |           id
197 |           name
198 |           entity_type
199 |           access_right
200 |         }
201 |       }
202 |     }
203 |   }
204 | }
205 | `;
206 | 
207 | export const ALL_TAXII_COLLECTIONS_QUERY = `
208 | query AllTaxiiCollections {
209 |   taxiiCollections {
210 |     edges {
211 |       node {
212 |         id
213 |         name
214 |         description
215 |         filters
216 |         include_inferences
217 |         score_to_confidence
218 |         taxii_public
219 |         authorized_members {
220 |           id
221 |           name
222 |           entity_type
223 |           access_right
224 |         }
225 |       }
226 |     }
227 |   }
228 | }
229 | `;
230 | 
231 | export const ALL_STREAM_COLLECTIONS_QUERY = `
232 | query AllStreamCollections {
233 |   streamCollections {
234 |     edges {
235 |       node {
236 |         id
237 |         name
238 |         description
239 |         filters
240 |         stream_live
241 |         stream_public
242 |         authorized_members {
243 |           id
244 |           name
245 |           entity_type
246 |           access_right
247 |         }
248 |       }
249 |     }
250 |   }
251 | }
252 | `;
253 | 
254 | export const ALL_RULES_QUERY = `
255 | query AllRules {
256 |   rules {
257 |     id
258 |     name
259 |     description
260 |     activated
261 |     category
262 |     display {
263 |       if {
264 |         source
265 |         source_color
266 |         relation
267 |         target
268 |         target_color
269 |         identifier
270 |         identifier_color
271 |         action
272 |       }
273 |       then {
274 |         source
275 |         source_color
276 |         relation
277 |         target
278 |         target_color
279 |         identifier
280 |         identifier_color
281 |         action
282 |       }
283 |     }
284 |   }
285 | }
286 | `;
287 | 
288 | export const ALL_SYNCHRONIZERS_QUERY = `
289 | query AllSynchronizers {
290 |   synchronizers {
291 |     edges {
292 |       node {
293 |         id
294 |         name
295 |         uri
296 |         token
297 |         stream_id
298 |         user {
299 |           id
300 |           name
301 |           entity_type
302 |         }
303 |         running
304 |         current_state_date
305 |         listen_deletion
306 |         no_dependencies
307 |         ssl_verify
308 |         synchronized
309 |         queue_messages
310 |       }
311 |     }
312 |   }
313 | }
314 | `;
315 | 
```

--------------------------------------------------------------------------------
/src/queries/stix_objects.ts:
--------------------------------------------------------------------------------

```typescript
  1 | export const REPORT_BY_ID_QUERY = `
  2 | query ReportById($id: String!) {
  3 |   report(id: $id) {
  4 |     id
  5 |     standard_id
  6 |     entity_type
  7 |     parent_types
  8 |     name
  9 |     description
 10 |     content
 11 |     content_mapping
 12 |     report_types
 13 |     published
 14 |     confidence
 15 |     createdBy {
 16 |       id
 17 |       name
 18 |       entity_type
 19 |     }
 20 |     objectMarking {
 21 |       id
 22 |       definition
 23 |       x_opencti_order
 24 |       x_opencti_color
 25 |     }
 26 |     objectLabel {
 27 |       id
 28 |       value
 29 |       color
 30 |     }
 31 |     externalReferences {
 32 |       edges {
 33 |         node {
 34 |           id
 35 |           source_name
 36 |           description
 37 |           url
 38 |           hash
 39 |           external_id
 40 |         }
 41 |       }
 42 |     }
 43 |     objects(first: 500) {
 44 |       edges {
 45 |         node {
 46 |           ... on StixDomainObject {
 47 |             id
 48 |             entity_type
 49 |             parent_types
 50 |             created
 51 |             updated_at
 52 |             standard_id
 53 |             created
 54 |             revoked
 55 |             confidence
 56 |             lang
 57 |             status {
 58 |               id
 59 |               template {
 60 |                 name
 61 |                 color
 62 |               }
 63 |             }
 64 |           }
 65 |           ... on StixCyberObservable {
 66 |             id
 67 |             entity_type
 68 |             parent_types
 69 |             observable_value
 70 |             x_opencti_description
 71 |             x_opencti_score
 72 |           }
 73 |           ... on StixCoreRelationship {
 74 |             id
 75 |             entity_type
 76 |             parent_types
 77 |             relationship_type
 78 |             description
 79 |             start_time
 80 |             stop_time
 81 |             from {
 82 |               ... on StixDomainObject {
 83 |                 id
 84 |                 entity_type
 85 |                 parent_types
 86 |                 created_at
 87 |                 standard_id
 88 |               }
 89 |             }
 90 |             to {
 91 |               ... on StixDomainObject {
 92 |                 id
 93 |                 entity_type
 94 |                 parent_types
 95 |                 created_at
 96 |                 standard_id
 97 |               }
 98 |             }
 99 |           }
100 |         }
101 |       }
102 |     }
103 |     created
104 |     modified
105 |     created_at
106 |     updated_at
107 |     x_opencti_stix_ids
108 |     status {
109 |       id
110 |       template {
111 |         name
112 |         color
113 |       }
114 |     }
115 |     workflowEnabled
116 |     containersNumber {
117 |       total
118 |       count
119 |     }
120 |     containers {
121 |       edges {
122 |         node {
123 |           id
124 |           entity_type
125 |           parent_types
126 |           created_at
127 |           standard_id
128 |         }
129 |       }
130 |     }
131 |   }
132 | }
133 | `;
134 | 
135 | export const ALL_ATTACK_PATTERNS_QUERY = `
136 | query AllAttackPatterns($first: Int, $after: ID) {
137 |   attackPatterns(first: $first, after: $after) {
138 |     pageInfo {
139 |       hasNextPage
140 |       endCursor
141 |     }
142 |     edges {
143 |       node {
144 |         id
145 |         standard_id
146 |         entity_type
147 |         parent_types
148 |         name
149 |         description
150 |         x_mitre_id
151 |         killChainPhases {
152 |           id
153 |           kill_chain_name
154 |           phase_name
155 |         }
156 |         coursesOfAction {
157 |           edges {
158 |             node {
159 |               id
160 |               name
161 |               description
162 |             }
163 |           }
164 |         }
165 |       }
166 |     }
167 |   }
168 | }
169 | `;
170 | 
171 | export const CAMPAIGN_BY_NAME_QUERY = `
172 | query CampaignByName($name: Any!) {
173 |   campaigns(
174 |     first: 1,
175 |     filters: {
176 |       mode: and,
177 |       filters: [
178 |         {
179 |           key: "name",
180 |           values: [$name],
181 |           operator: eq,
182 |           mode: or
183 |         }
184 |       ],
185 |       filterGroups: []
186 |     }
187 |   ) {
188 |     edges {
189 |       node {
190 |         id
191 |         standard_id
192 |         entity_type
193 |         parent_types
194 |         name
195 |         description
196 |         first_seen
197 |         last_seen
198 |         created
199 |         modified
200 |         created_at
201 |         updated_at
202 |       }
203 |     }
204 |   }
205 | }
206 | `;
207 | 
208 | export const ALL_STIX_CORE_OBJECTS_QUERY = `
209 | query AllStixCoreObjects {
210 |   stixCoreObjects {
211 |     edges {
212 |       node {
213 |         id
214 |         standard_id
215 |         entity_type
216 |         parent_types
217 |         representative {
218 |           main
219 |           secondary
220 |         }
221 |         x_opencti_stix_ids
222 |         is_inferred
223 |         spec_version
224 |         created_at
225 |         updated_at
226 |         createdBy {
227 |           id
228 |           name
229 |           entity_type
230 |         }
231 |         numberOfConnectedElement
232 |         objectMarking {
233 |           id
234 |           definition
235 |           x_opencti_order
236 |           x_opencti_color
237 |         }
238 |         objectOrganization {
239 |           id
240 |           name
241 |         }
242 |         objectLabel {
243 |           id
244 |           value
245 |           color
246 |         }
247 |         externalReferences {
248 |           edges {
249 |             node {
250 |               id
251 |               source_name
252 |               description
253 |               url
254 |               hash
255 |               external_id
256 |             }
257 |           }
258 |         }
259 |         containersNumber {
260 |           total
261 |           count
262 |         }
263 |         containers {
264 |           edges {
265 |             node {
266 |               id
267 |               entity_type
268 |               parent_types
269 |               created_at
270 |               standard_id
271 |             }
272 |           }
273 |         }
274 |         reports {
275 |           edges {
276 |             node {
277 |               id
278 |               name
279 |             }
280 |           }
281 |         }
282 |         notes {
283 |           edges {
284 |             node {
285 |               id
286 |               content
287 |             }
288 |           }
289 |         }
290 |         opinions {
291 |           edges {
292 |             node {
293 |               id
294 |               opinion
295 |             }
296 |           }
297 |         }
298 |         observedData {
299 |           edges {
300 |             node {
301 |               id
302 |               first_observed
303 |               last_observed
304 |               number_observed
305 |             }
306 |           }
307 |         }
308 |         groupings {
309 |           edges {
310 |             node {
311 |               id
312 |               name
313 |             }
314 |           }
315 |         }
316 |         cases {
317 |           edges {
318 |             node {
319 |               id
320 |               name
321 |             }
322 |           }
323 |         }
324 |       }
325 |     }
326 |   }
327 | }
328 | `;
329 | 
330 | export const ALL_STIX_DOMAIN_OBJECTS_QUERY = `
331 | query AllStixDomainObjects {
332 |   stixDomainObjects {
333 |     edges {
334 |       node {
335 |         id
336 |         standard_id
337 |         entity_type
338 |         parent_types
339 |         representative {
340 |           main
341 |           secondary
342 |         }
343 |         x_opencti_stix_ids
344 |         is_inferred
345 |         spec_version
346 |         created_at
347 |         updated_at
348 |         createdBy {
349 |           id
350 |           name
351 |           entity_type
352 |         }
353 |         numberOfConnectedElement
354 |         objectMarking {
355 |           id
356 |           definition
357 |           x_opencti_order
358 |           x_opencti_color
359 |         }
360 |         objectOrganization {
361 |           id
362 |           name
363 |         }
364 |         objectLabel {
365 |           id
366 |           value
367 |           color
368 |         }
369 |         externalReferences {
370 |           edges {
371 |             node {
372 |               id
373 |               source_name
374 |               description
375 |               url
376 |               hash
377 |               external_id
378 |             }
379 |           }
380 |         }
381 |         containersNumber {
382 |           total
383 |           count
384 |         }
385 |         containers {
386 |           edges {
387 |             node {
388 |               id
389 |               entity_type
390 |               parent_types
391 |               created_at
392 |               standard_id
393 |             }
394 |           }
395 |         }
396 |         reports {
397 |           edges {
398 |             node {
399 |               id
400 |               name
401 |             }
402 |           }
403 |         }
404 |         notes {
405 |           edges {
406 |             node {
407 |               id
408 |               content
409 |             }
410 |           }
411 |         }
412 |         opinions {
413 |           edges {
414 |             node {
415 |               id
416 |               opinion
417 |             }
418 |           }
419 |         }
420 |         observedData {
421 |           edges {
422 |             node {
423 |               id
424 |               first_observed
425 |               last_observed
426 |               number_observed
427 |             }
428 |           }
429 |         }
430 |         groupings {
431 |           edges {
432 |             node {
433 |               id
434 |               name
435 |             }
436 |           }
437 |         }
438 |         cases {
439 |           edges {
440 |             node {
441 |               id
442 |               name
443 |             }
444 |           }
445 |         }
446 |         revoked
447 |         confidence
448 |         lang
449 |         created
450 |         modified
451 |         x_opencti_graph_data
452 |         objectAssignee {
453 |           id
454 |           name
455 |           entity_type
456 |         }
457 |         objectParticipant {
458 |           id
459 |           name
460 |           entity_type
461 |         }
462 |         status {
463 |           id
464 |           template {
465 |             name
466 |             color
467 |           }
468 |         }
469 |         workflowEnabled
470 |       }
471 |     }
472 |   }
473 | }
474 | `;
475 | 
```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
  1 | #!/usr/bin/env node
  2 | import { Server } from '@modelcontextprotocol/sdk/server/index.js';
  3 | import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
  4 | import {
  5 |   CallToolRequestSchema,
  6 |   ErrorCode,
  7 |   ListToolsRequestSchema,
  8 |   McpError,
  9 | } from '@modelcontextprotocol/sdk/types.js';
 10 | import axios from 'axios';
 11 | import {
 12 |   LATEST_REPORTS_QUERY,
 13 |   SEARCH_MALWARE_QUERY,
 14 |   SEARCH_INDICATORS_QUERY,
 15 |   SEARCH_THREAT_ACTORS_QUERY,
 16 | } from './queries/reports.js';
 17 | import {
 18 |   USER_BY_ID_QUERY,
 19 |   ALL_USERS_QUERY,
 20 |   ALL_GROUPS_QUERY,
 21 |   ALL_ROLES_QUERY,
 22 |   ALL_CAPABILITIES_QUERY,
 23 | } from './queries/users.js';
 24 | import {
 25 |   REPORT_BY_ID_QUERY,
 26 |   ALL_ATTACK_PATTERNS_QUERY,
 27 |   CAMPAIGN_BY_NAME_QUERY,
 28 |   ALL_STIX_CORE_OBJECTS_QUERY,
 29 |   ALL_STIX_DOMAIN_OBJECTS_QUERY,
 30 | } from './queries/stix_objects.js';
 31 | import {
 32 |   ALL_STIX_CORE_RELATIONSHIPS_QUERY,
 33 |   ALL_STIX_SIGHTING_RELATIONSHIPS_QUERY,
 34 |   ALL_STIX_REF_RELATIONSHIPS_QUERY,
 35 |   ALL_STIX_RELATIONSHIPS_QUERY,
 36 | } from './queries/relationships.js';
 37 | import {
 38 |   ALL_CONNECTORS_QUERY,
 39 |   ALL_STATUS_TEMPLATES_QUERY,
 40 |   ALL_STATUSES_QUERY,
 41 |   ALL_SUB_TYPES_QUERY,
 42 |   ALL_RETENTION_RULES_QUERY,
 43 |   ALL_BACKGROUND_TASKS_QUERY,
 44 |   ALL_FEEDS_QUERY,
 45 |   ALL_TAXII_COLLECTIONS_QUERY,
 46 |   ALL_STREAM_COLLECTIONS_QUERY,
 47 |   ALL_RULES_QUERY,
 48 |   ALL_SYNCHRONIZERS_QUERY,
 49 | } from './queries/system.js';
 50 | import {
 51 |   FILE_BY_ID_QUERY,
 52 |   ALL_FILES_QUERY,
 53 |   ALL_INDEXED_FILES_QUERY,
 54 |   ALL_LOGS_QUERY,
 55 |   ALL_AUDITS_QUERY,
 56 |   ALL_ATTRIBUTES_QUERY,
 57 |   ALL_SCHEMA_ATTRIBUTE_NAMES_QUERY,
 58 |   ALL_FILTER_KEYS_SCHEMA_QUERY,
 59 | } from './queries/metadata.js';
 60 | import {
 61 |   ALL_MARKING_DEFINITIONS_QUERY,
 62 |   ALL_LABELS_QUERY,
 63 |   ALL_EXTERNAL_REFERENCES_QUERY,
 64 |   ALL_KILL_CHAIN_PHASES_QUERY,
 65 | } from './queries/references.js';
 66 | 
 67 | const OPENCTI_URL = process.env.OPENCTI_URL || 'http://localhost:8080';
 68 | const OPENCTI_TOKEN = process.env.OPENCTI_TOKEN;
 69 | 
 70 | if (!OPENCTI_TOKEN) {
 71 |   throw new Error('OPENCTI_TOKEN environment variable is required');
 72 | }
 73 | 
 74 | interface OpenCTIResponse {
 75 |   data: {
 76 |     stixObjects: Array<{
 77 |       id: string;
 78 |       name?: string;
 79 |       description?: string;
 80 |       created_at?: string;
 81 |       modified_at?: string;
 82 |       pattern?: string;
 83 |       valid_from?: string;
 84 |       valid_until?: string;
 85 |       x_opencti_score?: number;
 86 |       [key: string]: any;
 87 |     }>;
 88 |   };
 89 | }
 90 | 
 91 | class OpenCTIServer {
 92 |   private server: Server;
 93 |   private axiosInstance;
 94 | 
 95 |   constructor() {
 96 |     this.server = new Server(
 97 |       {
 98 |         name: 'opencti-server',
 99 |         version: '0.1.0',
100 |       },
101 |       {
102 |         capabilities: {
103 |           tools: {},
104 |         },
105 |       }
106 |     );
107 | 
108 |     this.axiosInstance = axios.create({
109 |       baseURL: OPENCTI_URL,
110 |       headers: {
111 |         'Authorization': `Bearer ${OPENCTI_TOKEN}`,
112 |         'Content-Type': 'application/json',
113 |       },
114 |     });
115 | 
116 |     this.setupTools();
117 |     
118 |     this.server.onerror = (error) => console.error('[MCP Error]', error);
119 |     process.on('SIGINT', async () => {
120 |       await this.server.close();
121 |       process.exit(0);
122 |     });
123 |   }
124 | 
125 |   private setupTools() {
126 |     this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
127 |       tools: [
128 |         // Reports
129 |         {
130 |           name: 'get_latest_reports',
131 |           description: '獲取最新的OpenCTI報告',
132 |           inputSchema: {
133 |             type: 'object',
134 |             properties: {
135 |               first: {
136 |                 type: 'number',
137 |                 description: '返回結果數量限制',
138 |                 default: 10,
139 |               },
140 |             },
141 |           },
142 |         },
143 |         {
144 |           name: 'get_report_by_id',
145 |           description: '根據ID獲取OpenCTI報告',
146 |           inputSchema: {
147 |             type: 'object',
148 |             properties: {
149 |               id: {
150 |                 type: 'string',
151 |                 description: '報告ID',
152 |               },
153 |             },
154 |             required: ['id'],
155 |           },
156 |         },
157 |         // Search
158 |         {
159 |           name: 'search_indicators',
160 |           description: '搜尋OpenCTI中的指標',
161 |           inputSchema: {
162 |             type: 'object',
163 |             properties: {
164 |               query: {
165 |                 type: 'string',
166 |                 description: '搜尋關鍵字',
167 |               },
168 |               first: {
169 |                 type: 'number',
170 |                 description: '返回結果數量限制',
171 |                 default: 10,
172 |               },
173 |             },
174 |             required: ['query'],
175 |           },
176 |         },
177 |         {
178 |           name: 'search_malware',
179 |           description: '搜尋OpenCTI中的惡意程式',
180 |           inputSchema: {
181 |             type: 'object',
182 |             properties: {
183 |               query: {
184 |                 type: 'string',
185 |                 description: '搜尋關鍵字',
186 |               },
187 |               first: {
188 |                 type: 'number',
189 |                 description: '返回結果數量限制',
190 |                 default: 10,
191 |               },
192 |             },
193 |             required: ['query'],
194 |           },
195 |         },
196 |         {
197 |           name: 'search_threat_actors',
198 |           description: '搜尋OpenCTI中的威脅行為者',
199 |           inputSchema: {
200 |             type: 'object',
201 |             properties: {
202 |               query: {
203 |                 type: 'string',
204 |                 description: '搜尋關鍵字',
205 |               },
206 |               first: {
207 |                 type: 'number',
208 |                 description: '返回結果數量限制',
209 |                 default: 10,
210 |               },
211 |             },
212 |             required: ['query'],
213 |           },
214 |         },
215 |         // Users & Groups
216 |         {
217 |           name: 'get_user_by_id',
218 |           description: '根據ID獲取使用者資訊',
219 |           inputSchema: {
220 |             type: 'object',
221 |             properties: {
222 |               id: {
223 |                 type: 'string',
224 |                 description: '使用者ID',
225 |               },
226 |             },
227 |             required: ['id'],
228 |           },
229 |         },
230 |         {
231 |           name: 'list_users',
232 |           description: '列出所有使用者',
233 |           inputSchema: {
234 |             type: 'object',
235 |             properties: {},
236 |           },
237 |         },
238 |         {
239 |           name: 'list_groups',
240 |           description: '列出所有群組',
241 |           inputSchema: {
242 |             type: 'object',
243 |             properties: {
244 |               first: {
245 |                 type: 'number',
246 |                 description: '返回結果數量限制',
247 |                 default: 10,
248 |               },
249 |             },
250 |           },
251 |         },
252 |         // STIX Objects
253 |         {
254 |           name: 'list_attack_patterns',
255 |           description: '列出所有攻擊模式',
256 |           inputSchema: {
257 |             type: 'object',
258 |             properties: {
259 |               first: {
260 |                 type: 'number',
261 |                 description: '返回結果數量限制',
262 |                 default: 10,
263 |               },
264 |             },
265 |           },
266 |         },
267 |         {
268 |           name: 'get_campaign_by_name',
269 |           description: '根據名稱獲取行動資訊',
270 |           inputSchema: {
271 |             type: 'object',
272 |             properties: {
273 |               name: {
274 |                 type: 'string',
275 |                 description: '行動名稱',
276 |               },
277 |             },
278 |             required: ['name'],
279 |           },
280 |         },
281 |         // System
282 |         {
283 |           name: 'list_connectors',
284 |           description: '列出所有連接器',
285 |           inputSchema: {
286 |             type: 'object',
287 |             properties: {},
288 |           },
289 |         },
290 |         {
291 |           name: 'list_status_templates',
292 |           description: '列出所有狀態模板',
293 |           inputSchema: {
294 |             type: 'object',
295 |             properties: {},
296 |           },
297 |         },
298 |         // Files
299 |         {
300 |           name: 'get_file_by_id',
301 |           description: '根據ID獲取檔案資訊',
302 |           inputSchema: {
303 |             type: 'object',
304 |             properties: {
305 |               id: {
306 |                 type: 'string',
307 |                 description: '檔案ID',
308 |               },
309 |             },
310 |             required: ['id'],
311 |           },
312 |         },
313 |         {
314 |           name: 'list_files',
315 |           description: '列出所有檔案',
316 |           inputSchema: {
317 |             type: 'object',
318 |             properties: {},
319 |           },
320 |         },
321 |         // References
322 |         {
323 |           name: 'list_marking_definitions',
324 |           description: '列出所有標記定義',
325 |           inputSchema: {
326 |             type: 'object',
327 |             properties: {},
328 |           },
329 |         },
330 |         {
331 |           name: 'list_labels',
332 |           description: '列出所有標籤',
333 |           inputSchema: {
334 |             type: 'object',
335 |             properties: {},
336 |           },
337 |         },
338 |       ],
339 |     }));
340 | 
341 |     this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
342 |       try {
343 |         let query = '';
344 |         let variables: any = {};
345 | 
346 |         switch (request.params.name) {
347 |           // Reports
348 |           case 'get_latest_reports':
349 |             query = LATEST_REPORTS_QUERY;
350 |             variables = {
351 |               first: typeof request.params.arguments?.first === 'number' ? request.params.arguments.first : 10,
352 |             };
353 |             break;
354 | 
355 |           case 'get_report_by_id':
356 |             if (!request.params.arguments?.id) {
357 |               throw new McpError(ErrorCode.InvalidParams, 'Report ID is required');
358 |             }
359 |             query = REPORT_BY_ID_QUERY;
360 |             variables = { id: request.params.arguments.id };
361 |             break;
362 | 
363 |           // Search
364 |           case 'search_indicators':
365 |             if (!request.params.arguments?.query) {
366 |               throw new McpError(ErrorCode.InvalidParams, 'Query parameter is required');
367 |             }
368 |             query = SEARCH_INDICATORS_QUERY;
369 |             variables = {
370 |               search: request.params.arguments.query,
371 |               first: typeof request.params.arguments.first === 'number' ? request.params.arguments.first : 10,
372 |             };
373 |             break;
374 | 
375 |           case 'search_malware':
376 |             if (!request.params.arguments?.query) {
377 |               throw new McpError(ErrorCode.InvalidParams, 'Query parameter is required');
378 |             }
379 |             query = SEARCH_MALWARE_QUERY;
380 |             variables = {
381 |               search: request.params.arguments.query,
382 |               first: typeof request.params.arguments.first === 'number' ? request.params.arguments.first : 10,
383 |             };
384 |             break;
385 | 
386 |           case 'search_threat_actors':
387 |             if (!request.params.arguments?.query) {
388 |               throw new McpError(ErrorCode.InvalidParams, 'Query parameter is required');
389 |             }
390 |             query = SEARCH_THREAT_ACTORS_QUERY;
391 |             variables = {
392 |               search: request.params.arguments.query,
393 |               first: typeof request.params.arguments.first === 'number' ? request.params.arguments.first : 10,
394 |             };
395 |             break;
396 | 
397 |           // Users & Groups
398 |           case 'get_user_by_id':
399 |             if (!request.params.arguments?.id) {
400 |               throw new McpError(ErrorCode.InvalidParams, 'User ID is required');
401 |             }
402 |             query = USER_BY_ID_QUERY;
403 |             variables = { id: request.params.arguments.id };
404 |             break;
405 | 
406 |           case 'list_users':
407 |             query = ALL_USERS_QUERY;
408 |             break;
409 | 
410 |           case 'list_groups':
411 |             query = ALL_GROUPS_QUERY;
412 |             variables = {
413 |               first: typeof request.params.arguments?.first === 'number' ? request.params.arguments.first : 10,
414 |             };
415 |             break;
416 | 
417 |           // STIX Objects
418 |           case 'list_attack_patterns':
419 |             query = ALL_ATTACK_PATTERNS_QUERY;
420 |             variables = {
421 |               first: typeof request.params.arguments?.first === 'number' ? request.params.arguments.first : 10,
422 |             };
423 |             break;
424 | 
425 |           case 'get_campaign_by_name':
426 |             if (!request.params.arguments?.name) {
427 |               throw new McpError(ErrorCode.InvalidParams, 'Campaign name is required');
428 |             }
429 |             query = CAMPAIGN_BY_NAME_QUERY;
430 |             variables = { name: request.params.arguments.name };
431 |             break;
432 | 
433 |           // System
434 |           case 'list_connectors':
435 |             query = ALL_CONNECTORS_QUERY;
436 |             break;
437 | 
438 |           case 'list_status_templates':
439 |             query = ALL_STATUS_TEMPLATES_QUERY;
440 |             break;
441 | 
442 |           // Files
443 |           case 'get_file_by_id':
444 |             if (!request.params.arguments?.id) {
445 |               throw new McpError(ErrorCode.InvalidParams, 'File ID is required');
446 |             }
447 |             query = FILE_BY_ID_QUERY;
448 |             variables = { id: request.params.arguments.id };
449 |             break;
450 | 
451 |           case 'list_files':
452 |             query = ALL_FILES_QUERY;
453 |             break;
454 | 
455 |           // References
456 |           case 'list_marking_definitions':
457 |             query = ALL_MARKING_DEFINITIONS_QUERY;
458 |             break;
459 | 
460 |           case 'list_labels':
461 |             query = ALL_LABELS_QUERY;
462 |             break;
463 | 
464 |           default:
465 |             throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`);
466 |         }
467 | 
468 |         const response = await this.axiosInstance.post('/graphql', {
469 |           query,
470 |           variables,
471 |         });
472 | 
473 |         console.error('OpenCTI Response:', JSON.stringify(response.data, null, 2));
474 |         
475 |         if (!response.data?.data) {
476 |           throw new McpError(
477 |             ErrorCode.InternalError,
478 |             `Invalid response format from OpenCTI: ${JSON.stringify(response.data)}`
479 |           );
480 |         }
481 | 
482 |         let formattedResponse;
483 |         
484 |         switch (request.params.name) {
485 |           case 'get_latest_reports':
486 |             formattedResponse = response.data.data.reports.edges.map((edge: any) => ({
487 |               id: edge.node.id,
488 |               name: edge.node.name || 'Unnamed',
489 |               description: edge.node.description || '',
490 |               content: edge.node.content || '',
491 |               published: edge.node.published,
492 |               confidence: edge.node.confidence,
493 |               created: edge.node.created,
494 |               modified: edge.node.modified,
495 |               reportTypes: edge.node.report_types || [],
496 |             }));
497 |             break;
498 | 
499 |           case 'get_report_by_id':
500 |             formattedResponse = {
501 |               ...response.data.data.report,
502 |               name: response.data.data.report.name || 'Unnamed',
503 |               description: response.data.data.report.description || '',
504 |             };
505 |             break;
506 | 
507 |           case 'search_indicators':
508 |           case 'search_malware':
509 |           case 'search_threat_actors':
510 |             formattedResponse = response.data.data.stixCoreObjects.edges.map((edge: any) => ({
511 |               id: edge.node.id,
512 |               name: edge.node.name || 'Unnamed',
513 |               description: edge.node.description || '',
514 |               created: edge.node.created,
515 |               modified: edge.node.modified,
516 |               type: edge.node.malware_types?.join(', ') || edge.node.threat_actor_types?.join(', ') || '',
517 |               family: edge.node.is_family ? 'Yes' : 'No',
518 |               firstSeen: edge.node.first_seen || '',
519 |               lastSeen: edge.node.last_seen || '',
520 |               pattern: edge.node.pattern || '',
521 |               validFrom: edge.node.valid_from || '',
522 |               validUntil: edge.node.valid_until || '',
523 |               score: edge.node.x_opencti_score,
524 |             }));
525 |             break;
526 | 
527 |           case 'get_user_by_id':
528 |             formattedResponse = {
529 |               ...response.data.data.user,
530 |               name: response.data.data.user.name || 'Unnamed',
531 |             };
532 |             break;
533 | 
534 |           case 'list_users':
535 |             formattedResponse = response.data.data.users.edges.map((edge: any) => ({
536 |               id: edge.node.id,
537 |               name: edge.node.name || 'Unnamed',
538 |               email: edge.node.user_email,
539 |               firstname: edge.node.firstname,
540 |               lastname: edge.node.lastname,
541 |               created: edge.node.created_at,
542 |               modified: edge.node.updated_at,
543 |             }));
544 |             break;
545 | 
546 |           case 'list_groups':
547 |             formattedResponse = response.data.data.groups.edges.map((edge: any) => ({
548 |               id: edge.node.id,
549 |               name: edge.node.name || 'Unnamed',
550 |               description: edge.node.description || '',
551 |               members: edge.node.members?.edges?.map((memberEdge: any) => ({
552 |                 id: memberEdge.node.id,
553 |                 name: memberEdge.node.name,
554 |                 email: memberEdge.node.user_email,
555 |               })) || [],
556 |             }));
557 |             break;
558 | 
559 |           case 'list_attack_patterns':
560 |             formattedResponse = response.data.data.attackPatterns.edges.map((edge: any) => ({
561 |               id: edge.node.id,
562 |               name: edge.node.name || 'Unnamed',
563 |               description: edge.node.description || '',
564 |               created: edge.node.created_at,
565 |               modified: edge.node.updated_at,
566 |               killChainPhases: edge.node.killChainPhases?.edges?.map((phaseEdge: any) => ({
567 |                 id: phaseEdge.node.id,
568 |                 name: phaseEdge.node.phase_name,
569 |               })) || [],
570 |             }));
571 |             break;
572 | 
573 |           case 'list_connectors':
574 |             formattedResponse = response.data.data.connectors.map((connector: any) => ({
575 |               id: connector.id,
576 |               name: connector.name || 'Unnamed',
577 |               type: connector.connector_type,
578 |               scope: connector.connector_scope,
579 |               state: connector.connector_state,
580 |               active: connector.active,
581 |               updated: connector.updated_at,
582 |               created: connector.created_at,
583 |             }));
584 |             break;
585 | 
586 |           case 'list_status_templates':
587 |             formattedResponse = response.data.data.statusTemplates.edges.map((edge: any) => ({
588 |               id: edge.node.id,
589 |               name: edge.node.name || 'Unnamed',
590 |               color: edge.node.color,
591 |               usages: edge.node.usages,
592 |             }));
593 |             break;
594 | 
595 |           case 'list_marking_definitions':
596 |             formattedResponse = response.data.data.markingDefinitions.edges.map((edge: any) => ({
597 |               id: edge.node.id,
598 |               definition: edge.node.definition,
599 |               color: edge.node.x_opencti_color,
600 |               order: edge.node.x_opencti_order,
601 |             }));
602 |             break;
603 | 
604 |           case 'list_labels':
605 |             formattedResponse = response.data.data.labels.edges.map((edge: any) => ({
606 |               id: edge.node.id,
607 |               value: edge.node.value,
608 |               color: edge.node.color,
609 |             }));
610 |             break;
611 | 
612 |           default:
613 |             formattedResponse = response.data.data;
614 |         }
615 | 
616 |         return {
617 |           content: [{
618 |             type: 'text',
619 |             text: JSON.stringify(formattedResponse, null, 2)
620 |           }]
621 |         };
622 |       } catch (error) {
623 |         if (axios.isAxiosError(error)) {
624 |           console.error('Axios Error:', error.response?.data);
625 |           return {
626 |             content: [{
627 |               type: 'text',
628 |               text: `OpenCTI API error: ${JSON.stringify(error.response?.data) || error.message}`
629 |             }],
630 |             isError: true,
631 |           };
632 |         }
633 |         throw error;
634 |       }
635 |     });
636 |   }
637 | 
638 |   async run() {
639 |     const transport = new StdioServerTransport();
640 |     await this.server.connect(transport);
641 |     console.error('OpenCTI MCP server running on stdio');
642 |   }
643 | }
644 | 
645 | const server = new OpenCTIServer();
646 | server.run().catch(console.error);
647 | 
```
Page 1/2FirstPrevNextLast