@certynix/mcp 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/CHANGELOG.md +49 -0
- package/README.md +209 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +119 -0
- package/dist/prompts/audit-report.d.ts +6 -0
- package/dist/prompts/audit-report.js +117 -0
- package/dist/prompts/security-review.d.ts +6 -0
- package/dist/prompts/security-review.js +95 -0
- package/dist/resources/alerts-active.d.ts +7 -0
- package/dist/resources/alerts-active.js +43 -0
- package/dist/resources/asset.d.ts +7 -0
- package/dist/resources/asset.js +61 -0
- package/dist/resources/organization-info.d.ts +8 -0
- package/dist/resources/organization-info.js +44 -0
- package/dist/resources/trust-score.d.ts +7 -0
- package/dist/resources/trust-score.js +46 -0
- package/dist/server.d.ts +13 -0
- package/dist/server.js +67 -0
- package/dist/tools/create-api-key.d.ts +3 -0
- package/dist/tools/create-api-key.js +37 -0
- package/dist/tools/create-webhook.d.ts +3 -0
- package/dist/tools/create-webhook.js +45 -0
- package/dist/tools/delete-asset.d.ts +3 -0
- package/dist/tools/delete-asset.js +48 -0
- package/dist/tools/get-asset.d.ts +3 -0
- package/dist/tools/get-asset.js +41 -0
- package/dist/tools/get-trust-score.d.ts +3 -0
- package/dist/tools/get-trust-score.js +43 -0
- package/dist/tools/list-alerts.d.ts +3 -0
- package/dist/tools/list-alerts.js +55 -0
- package/dist/tools/list-api-keys.d.ts +3 -0
- package/dist/tools/list-api-keys.js +51 -0
- package/dist/tools/list-assets.d.ts +3 -0
- package/dist/tools/list-assets.js +68 -0
- package/dist/tools/list-audit-logs.d.ts +3 -0
- package/dist/tools/list-audit-logs.js +62 -0
- package/dist/tools/list-webhooks.d.ts +3 -0
- package/dist/tools/list-webhooks.js +51 -0
- package/dist/tools/register-asset.d.ts +3 -0
- package/dist/tools/register-asset.js +87 -0
- package/dist/tools/revoke-api-key.d.ts +3 -0
- package/dist/tools/revoke-api-key.js +48 -0
- package/dist/tools/verify-asset.d.ts +3 -0
- package/dist/tools/verify-asset.js +53 -0
- package/dist/tools/verify-webhook-signature.d.ts +7 -0
- package/dist/tools/verify-webhook-signature.js +178 -0
- package/dist/utils/format.d.ts +10 -0
- package/dist/utils/format.js +18 -0
- package/dist/utils/mask.d.ts +14 -0
- package/dist/utils/mask.js +42 -0
- package/eslint.config.mjs +27 -0
- package/package.json +38 -0
- package/src/index.ts +149 -0
- package/src/prompts/audit-report.ts +126 -0
- package/src/prompts/security-review.ts +102 -0
- package/src/resources/alerts-active.ts +56 -0
- package/src/resources/asset.ts +79 -0
- package/src/resources/organization-info.ts +60 -0
- package/src/resources/trust-score.ts +59 -0
- package/src/server.ts +81 -0
- package/src/tools/create-api-key.ts +52 -0
- package/src/tools/create-webhook.ts +63 -0
- package/src/tools/delete-asset.ts +63 -0
- package/src/tools/get-asset.ts +53 -0
- package/src/tools/get-trust-score.ts +57 -0
- package/src/tools/list-alerts.ts +69 -0
- package/src/tools/list-api-keys.ts +63 -0
- package/src/tools/list-assets.ts +80 -0
- package/src/tools/list-audit-logs.ts +76 -0
- package/src/tools/list-webhooks.ts +63 -0
- package/src/tools/register-asset.ts +103 -0
- package/src/tools/revoke-api-key.ts +65 -0
- package/src/tools/verify-asset.ts +66 -0
- package/src/tools/verify-webhook-signature.ts +232 -0
- package/src/utils/format.ts +20 -0
- package/src/utils/mask.ts +41 -0
- package/tests/unit/tools/register-asset.test.ts +190 -0
- package/tests/unit/tools/verify-webhook-signature.test.ts +250 -0
- package/tests/unit/utils/mask.test.ts +129 -0
- package/tsconfig.json +17 -0
- package/vitest.config.ts +19 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@certynix/mcp` will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## [1.0.0] - 2026-03-15
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Initial release of `@certynix/mcp` — Official Certynix MCP Server
|
|
15
|
+
- **14 Tools:**
|
|
16
|
+
- `register_asset` — Register digital assets via SHA-256 hash, URL, or base64 file
|
|
17
|
+
- `verify_asset` — Public asset authenticity verification (no quota consumed)
|
|
18
|
+
- `list_assets` — List organization assets with filters and cursor-based pagination
|
|
19
|
+
- `get_asset` — Fetch a specific asset by ID with full metadata
|
|
20
|
+
- `delete_asset` — Soft delete an asset (requires `confirm: true`)
|
|
21
|
+
- `list_alerts` — List Exposure Alerts with severity and resolved filters
|
|
22
|
+
- `get_trust_score` — Fetch Trust Score V2 with all 4 pillar components and penalties
|
|
23
|
+
- `list_audit_logs` — List audit trail with action type and date range filters
|
|
24
|
+
- `create_api_key` — Create a new API Key (full key shown only once)
|
|
25
|
+
- `list_api_keys` — List API Keys (prefix only, never full value)
|
|
26
|
+
- `revoke_api_key` — Revoke an API Key immediately (requires `confirm: true`)
|
|
27
|
+
- `create_webhook` — Create webhook endpoint (signing_secret shown only once)
|
|
28
|
+
- `list_webhooks` — List webhooks (signing_secret never returned)
|
|
29
|
+
- `verify_webhook_signature` — Local HMAC-SHA256 webhook signature verification
|
|
30
|
+
- **4 Resources:**
|
|
31
|
+
- `certynix://organization/info` — Authenticated organization info
|
|
32
|
+
- `certynix://organization/trust-score` — Trust Score V2 with components and penalties
|
|
33
|
+
- `certynix://assets/{asset_id}` — Full asset metadata (URI template)
|
|
34
|
+
- `certynix://alerts/active` — Active (unresolved) Exposure Alerts
|
|
35
|
+
- **2 Prompts:**
|
|
36
|
+
- `certynix_audit_report` — Structured audit report for a specified period
|
|
37
|
+
- `certynix_security_review` — Complete organization security analysis with recommendations
|
|
38
|
+
- **Transports:**
|
|
39
|
+
- `stdio` transport — for Claude Desktop, Cursor, Windsurf and local tools
|
|
40
|
+
- `sse` transport — for remote agents, cloud platforms and web integrations
|
|
41
|
+
- **Security features:**
|
|
42
|
+
- Automatic sandbox detection via API key prefix (`cnx_test_sk_*`)
|
|
43
|
+
- API key masking (`maskApiKey()`) in all logs and error messages
|
|
44
|
+
- `sanitizeForOutput()` removes sensitive fields recursively from all outputs
|
|
45
|
+
- Destructive action confirmation (`confirm: true` required for `delete_asset` and `revoke_api_key`)
|
|
46
|
+
- Local HMAC-SHA256 webhook signature verification with constant-time comparison
|
|
47
|
+
- Anti-replay protection: timestamps older than 5 minutes are rejected
|
|
48
|
+
- Future timestamp detection: timestamps > 60s in the future are rejected
|
|
49
|
+
- `organization_id` never accepted as a tool parameter (always resolved via API Key)
|
package/README.md
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# @certynix/mcp — Official Certynix MCP Server
|
|
2
|
+
|
|
3
|
+
> **Expose the Certynix Trust Infrastructure to AI agents via Model Context Protocol.**
|
|
4
|
+
> Connect Claude Desktop, Cursor, Windsurf, LangChain, CrewAI, and any MCP-compatible system to the Certynix API.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## What is this?
|
|
9
|
+
|
|
10
|
+
`@certynix/mcp` is an MCP (Model Context Protocol) server that acts as a bridge between AI agents and the Certynix API. It exposes the Trust Infrastructure capabilities as **tools**, **resources**, and **prompts** that any MCP client can consume.
|
|
11
|
+
|
|
12
|
+
**Use cases:**
|
|
13
|
+
|
|
14
|
+
- AI agent that automatically registers assets in a CI/CD pipeline
|
|
15
|
+
- Claude verifying the authenticity of a contract before analyzing it
|
|
16
|
+
- Agent monitoring Exposure Alerts and taking corrective actions
|
|
17
|
+
- Audit automation: audit log listing and analysis via prompt
|
|
18
|
+
- Document approval workflow integration
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install -g @certynix/mcp
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Configuration
|
|
31
|
+
|
|
32
|
+
### Environment variables
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# REQUIRED
|
|
36
|
+
CERTYNIX_API_KEY=cnx_live_sk_... # Production key
|
|
37
|
+
# or
|
|
38
|
+
CERTYNIX_API_KEY=cnx_test_sk_... # Sandbox key (auto-detected)
|
|
39
|
+
|
|
40
|
+
# OPTIONAL
|
|
41
|
+
CERTYNIX_BASE_URL=https://api.certynix.com # Auto-detected from key prefix
|
|
42
|
+
CERTYNIX_TIMEOUT=30000 # Request timeout in ms (default: 30000)
|
|
43
|
+
MCP_TRANSPORT=stdio # stdio | sse (default: stdio)
|
|
44
|
+
MCP_PORT=3100 # SSE port (default: 3100, sse only)
|
|
45
|
+
MCP_LOG_LEVEL=info # debug | info | warn | error
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Sandbox mode
|
|
49
|
+
|
|
50
|
+
API keys prefixed with `cnx_test_sk_` automatically connect to the sandbox environment (`https://sandbox.certynix.com`). No configuration needed.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Claude Desktop
|
|
55
|
+
|
|
56
|
+
Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"mcpServers": {
|
|
61
|
+
"certynix": {
|
|
62
|
+
"command": "npx",
|
|
63
|
+
"args": ["-y", "@certynix/mcp"],
|
|
64
|
+
"env": {
|
|
65
|
+
"CERTYNIX_API_KEY": "cnx_live_sk_..."
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Or if installed globally:
|
|
73
|
+
|
|
74
|
+
```json
|
|
75
|
+
{
|
|
76
|
+
"mcpServers": {
|
|
77
|
+
"certynix": {
|
|
78
|
+
"command": "certynix-mcp",
|
|
79
|
+
"env": {
|
|
80
|
+
"CERTYNIX_API_KEY": "cnx_live_sk_..."
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Cursor / Windsurf
|
|
90
|
+
|
|
91
|
+
Add to `~/.cursor/mcp.json` (Cursor) or the equivalent Windsurf config:
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"mcpServers": {
|
|
96
|
+
"certynix": {
|
|
97
|
+
"command": "certynix-mcp",
|
|
98
|
+
"env": {
|
|
99
|
+
"CERTYNIX_API_KEY": "cnx_live_sk_..."
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## SSE Transport (remote agents)
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
# Start SSE server
|
|
112
|
+
CERTYNIX_API_KEY=cnx_live_sk_... MCP_TRANSPORT=sse MCP_PORT=3100 certynix-mcp
|
|
113
|
+
|
|
114
|
+
# Endpoints:
|
|
115
|
+
# SSE: http://localhost:3100/sse
|
|
116
|
+
# Messages: http://localhost:3100/message
|
|
117
|
+
# Health check: http://localhost:3100/health
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Docker
|
|
121
|
+
|
|
122
|
+
```dockerfile
|
|
123
|
+
FROM node:20-alpine
|
|
124
|
+
RUN npm install -g @certynix/mcp
|
|
125
|
+
ENV MCP_TRANSPORT=sse
|
|
126
|
+
ENV MCP_PORT=3100
|
|
127
|
+
EXPOSE 3100
|
|
128
|
+
CMD ["certynix-mcp"]
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Tools (14)
|
|
134
|
+
|
|
135
|
+
| Tool | Description |
|
|
136
|
+
|------|-------------|
|
|
137
|
+
| `register_asset` | Register a digital asset via SHA-256 hash, public URL, or base64 file content |
|
|
138
|
+
| `verify_asset` | Publicly verify asset authenticity — no auth required, no quota consumed |
|
|
139
|
+
| `list_assets` | List organization assets with status and date filters, cursor pagination |
|
|
140
|
+
| `get_asset` | Fetch a specific asset by ID with full metadata and event history |
|
|
141
|
+
| `delete_asset` | Soft delete an asset — irreversible, requires `confirm: true` |
|
|
142
|
+
| `list_alerts` | List Exposure Alerts with severity and resolved status filters |
|
|
143
|
+
| `get_trust_score` | Get Trust Score V2: score 0-100, 4-pillar breakdown, active penalties |
|
|
144
|
+
| `list_audit_logs` | List complete audit trail with action type and date range filters |
|
|
145
|
+
| `create_api_key` | Create a new API Key — full key shown only once, store immediately |
|
|
146
|
+
| `list_api_keys` | List API Keys — prefix only, full key never returned |
|
|
147
|
+
| `revoke_api_key` | Revoke an API Key immediately — irreversible, requires `confirm: true` |
|
|
148
|
+
| `create_webhook` | Create a webhook endpoint — signing_secret shown only at creation |
|
|
149
|
+
| `list_webhooks` | List webhooks — signing_secret never returned in listings |
|
|
150
|
+
| `verify_webhook_signature` | Local HMAC-SHA256 webhook signature verification (no API call) |
|
|
151
|
+
|
|
152
|
+
### Usage examples with Claude
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
"Register this document on Certynix:
|
|
156
|
+
SHA-256 hash: a3f4b2c1d8e9f0123456789abcdef0123456789abcdef0123456789abcdef01
|
|
157
|
+
filename: service-contract-2026.pdf"
|
|
158
|
+
|
|
159
|
+
"Verify if the file with hash e3b0c44298fc1c149afbf4c8996fb924...
|
|
160
|
+
has been certified by anyone"
|
|
161
|
+
|
|
162
|
+
"List the last 10 high-severity Exposure Alerts"
|
|
163
|
+
|
|
164
|
+
"Generate a security review of our organization"
|
|
165
|
+
|
|
166
|
+
"Create an API Key called 'CI/CD Pipeline - GitHub Actions'"
|
|
167
|
+
|
|
168
|
+
"Show me all active Exposure Alerts"
|
|
169
|
+
|
|
170
|
+
"What is our current Trust Score?"
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Resources (4)
|
|
176
|
+
|
|
177
|
+
| URI | Description |
|
|
178
|
+
|-----|-------------|
|
|
179
|
+
| `certynix://organization/info` | Authenticated organization info: name, plan, Trust Score |
|
|
180
|
+
| `certynix://organization/trust-score` | Trust Score V2 with component breakdown and active penalties |
|
|
181
|
+
| `certynix://assets/{asset_id}` | Full asset metadata by ID (URI template) |
|
|
182
|
+
| `certynix://alerts/active` | Active (unresolved) Exposure Alerts |
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Prompts (2)
|
|
187
|
+
|
|
188
|
+
| Prompt | Description |
|
|
189
|
+
|--------|-------------|
|
|
190
|
+
| `certynix_audit_report` | Generate a structured audit report for a period (`last_7_days`, `last_30_days`, `custom`) |
|
|
191
|
+
| `certynix_security_review` | Complete organization security analysis: Trust Score, penalties, API Keys, alerts, recommendations |
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Security
|
|
196
|
+
|
|
197
|
+
- **API Key never exposed**: masked in all logs as `cnx_live_sk_***`
|
|
198
|
+
- **Sensitive fields sanitized**: `api_key`, `secret`, `token`, `password`, `signing_secret` replaced with `***` in all outputs
|
|
199
|
+
- **Destructive actions require confirmation**: `delete_asset` and `revoke_api_key` require `confirm: true`
|
|
200
|
+
- **`organization_id` never accepted as parameter**: always resolved server-side via API Key
|
|
201
|
+
- **Webhook verification is constant-time**: prevents HMAC timing attacks
|
|
202
|
+
- **Anti-replay protection**: webhook timestamps older than 5 minutes are rejected
|
|
203
|
+
- **Signing secret shown only once**: at webhook creation — never returned in listings
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## Changelog
|
|
208
|
+
|
|
209
|
+
See [CHANGELOG.md](./CHANGELOG.md) for release history.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Certynix MCP Server — Entrypoint
|
|
4
|
+
*
|
|
5
|
+
* Expõe a Certynix Trust Infrastructure para agentes de IA via Model Context Protocol.
|
|
6
|
+
* Suporta transporte stdio (Claude Desktop) e SSE (integrações remotas).
|
|
7
|
+
*
|
|
8
|
+
* Variáveis de ambiente:
|
|
9
|
+
* CERTYNIX_API_KEY — obrigatório (cnx_live_sk_* ou cnx_test_sk_*)
|
|
10
|
+
* CERTYNIX_BASE_URL — opcional (auto-detectado via prefixo da key)
|
|
11
|
+
* CERTYNIX_TIMEOUT — opcional (ms, padrão: 30000)
|
|
12
|
+
* MCP_TRANSPORT — opcional (stdio | sse, padrão: stdio)
|
|
13
|
+
* MCP_PORT — opcional (apenas para sse, padrão: 3100)
|
|
14
|
+
* MCP_LOG_LEVEL — opcional (debug | info | warn | error, padrão: info)
|
|
15
|
+
*/
|
|
16
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Certynix MCP Server — Entrypoint
|
|
4
|
+
*
|
|
5
|
+
* Expõe a Certynix Trust Infrastructure para agentes de IA via Model Context Protocol.
|
|
6
|
+
* Suporta transporte stdio (Claude Desktop) e SSE (integrações remotas).
|
|
7
|
+
*
|
|
8
|
+
* Variáveis de ambiente:
|
|
9
|
+
* CERTYNIX_API_KEY — obrigatório (cnx_live_sk_* ou cnx_test_sk_*)
|
|
10
|
+
* CERTYNIX_BASE_URL — opcional (auto-detectado via prefixo da key)
|
|
11
|
+
* CERTYNIX_TIMEOUT — opcional (ms, padrão: 30000)
|
|
12
|
+
* MCP_TRANSPORT — opcional (stdio | sse, padrão: stdio)
|
|
13
|
+
* MCP_PORT — opcional (apenas para sse, padrão: 3100)
|
|
14
|
+
* MCP_LOG_LEVEL — opcional (debug | info | warn | error, padrão: info)
|
|
15
|
+
*/
|
|
16
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
17
|
+
import { createServer } from './server.js';
|
|
18
|
+
import { maskApiKey } from './utils/mask.js';
|
|
19
|
+
async function main() {
|
|
20
|
+
const apiKey = process.env['CERTYNIX_API_KEY'];
|
|
21
|
+
if (!apiKey) {
|
|
22
|
+
console.error('Error: CERTYNIX_API_KEY environment variable is required.\n' +
|
|
23
|
+
'Set it to your Certynix API Key (cnx_live_sk_... for production, cnx_test_sk_... for sandbox).');
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
// Validar formato básico sem expor a key
|
|
27
|
+
if (!apiKey.startsWith('cnx_live_sk_') && !apiKey.startsWith('cnx_test_sk_')) {
|
|
28
|
+
console.error('Error: Invalid CERTYNIX_API_KEY format.\n' +
|
|
29
|
+
'Expected: cnx_live_sk_... (production) or cnx_test_sk_... (sandbox).');
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
const transport = process.env['MCP_TRANSPORT'] ?? 'stdio';
|
|
33
|
+
const baseUrl = process.env['CERTYNIX_BASE_URL'];
|
|
34
|
+
const timeoutRaw = process.env['CERTYNIX_TIMEOUT'];
|
|
35
|
+
const timeout = timeoutRaw !== undefined ? parseInt(timeoutRaw, 10) : undefined;
|
|
36
|
+
const isSandbox = apiKey.startsWith('cnx_test_sk_');
|
|
37
|
+
let server;
|
|
38
|
+
try {
|
|
39
|
+
server = createServer(apiKey, {
|
|
40
|
+
...(baseUrl !== undefined ? { baseUrl } : {}),
|
|
41
|
+
...(timeout !== undefined ? { timeout } : {}),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
// Nunca logar a API key, mesmo em erro de inicialização
|
|
46
|
+
console.error('Failed to initialize Certynix MCP Server. Check your API key format and network connectivity.');
|
|
47
|
+
if (err instanceof Error) {
|
|
48
|
+
// Sanitizar mensagem de erro para garantir que a key não vaze
|
|
49
|
+
const sanitized = err.message.replace(apiKey, maskApiKey(apiKey));
|
|
50
|
+
console.error(`Details: ${sanitized}`);
|
|
51
|
+
}
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
if (transport === 'stdio') {
|
|
55
|
+
const stdioTransport = new StdioServerTransport();
|
|
56
|
+
await server.connect(stdioTransport);
|
|
57
|
+
// Log para stderr (não interfere com stdio MCP) — API key mascarada
|
|
58
|
+
console.error(`Certynix MCP Server running (stdio) — ` +
|
|
59
|
+
`API key: ${maskApiKey(apiKey)} — ` +
|
|
60
|
+
`Environment: ${isSandbox ? 'sandbox' : 'production'}`);
|
|
61
|
+
}
|
|
62
|
+
else if (transport === 'sse') {
|
|
63
|
+
const port = parseInt(process.env['MCP_PORT'] ?? '3100', 10);
|
|
64
|
+
// SSE transport via HTTP server
|
|
65
|
+
// Importação dinâmica para evitar dependência quando não for necessário
|
|
66
|
+
const { createServer: createHttpServer } = await import('node:http');
|
|
67
|
+
const { SSEServerTransport } = await import('@modelcontextprotocol/sdk/server/sse.js');
|
|
68
|
+
const httpServer = createHttpServer();
|
|
69
|
+
let sseTransport = null;
|
|
70
|
+
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
71
|
+
httpServer.on('request', async (req, res) => {
|
|
72
|
+
if (req.method === 'GET' && req.url === '/sse') {
|
|
73
|
+
sseTransport = new SSEServerTransport('/message', res);
|
|
74
|
+
await server.connect(sseTransport);
|
|
75
|
+
console.error(`Certynix MCP SSE client connected from ${req.socket.remoteAddress ?? 'unknown'}`);
|
|
76
|
+
}
|
|
77
|
+
else if (req.method === 'POST' && req.url === '/message') {
|
|
78
|
+
if (!sseTransport) {
|
|
79
|
+
res.writeHead(503, { 'Content-Type': 'application/json' });
|
|
80
|
+
res.end(JSON.stringify({ error: 'SSE connection not established yet' }));
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
await sseTransport.handlePostMessage(req, res);
|
|
84
|
+
}
|
|
85
|
+
else if (req.method === 'GET' && req.url === '/health') {
|
|
86
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
87
|
+
res.end(JSON.stringify({
|
|
88
|
+
status: 'ok',
|
|
89
|
+
server: 'certynix-mcp',
|
|
90
|
+
version: '1.0.0',
|
|
91
|
+
environment: isSandbox ? 'sandbox' : 'production',
|
|
92
|
+
}));
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
96
|
+
res.end(JSON.stringify({ error: 'Not found' }));
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
await new Promise((resolve, reject) => {
|
|
100
|
+
httpServer.listen(port, () => {
|
|
101
|
+
console.error(`Certynix MCP Server running on port ${port} (SSE) — ` +
|
|
102
|
+
`API key: ${maskApiKey(apiKey)} — ` +
|
|
103
|
+
`Environment: ${isSandbox ? 'sandbox' : 'production'}\n` +
|
|
104
|
+
` SSE endpoint: http://localhost:${port}/sse\n` +
|
|
105
|
+
` Health check: http://localhost:${port}/health`);
|
|
106
|
+
resolve();
|
|
107
|
+
});
|
|
108
|
+
httpServer.on('error', reject);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
console.error(`Error: Invalid MCP_TRANSPORT value: "${transport}". Expected "stdio" or "sse".`);
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
main().catch((err) => {
|
|
117
|
+
console.error('Fatal error:', err instanceof Error ? err.message : String(err));
|
|
118
|
+
process.exit(1);
|
|
119
|
+
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
/**
|
|
3
|
+
* Prompt: certynix_audit_report
|
|
4
|
+
* Gera um relatório de auditoria estruturado a partir dos audit logs da organização.
|
|
5
|
+
*/
|
|
6
|
+
export declare function registerAuditReportPrompt(server: McpServer): void;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Prompt: certynix_audit_report
|
|
4
|
+
* Gera um relatório de auditoria estruturado a partir dos audit logs da organização.
|
|
5
|
+
*/
|
|
6
|
+
export function registerAuditReportPrompt(server) {
|
|
7
|
+
server.prompt('certynix_audit_report', 'Gera um relatório de auditoria estruturado para um período específico, analisando ações críticas, padrões de acesso e eventos de segurança.', {
|
|
8
|
+
period: z
|
|
9
|
+
.enum(['last_7_days', 'last_30_days', 'custom'])
|
|
10
|
+
.describe("Período do relatório: 'last_7_days' (últimos 7 dias), 'last_30_days' (últimos 30 dias), 'custom' (usar start_date e end_date)."),
|
|
11
|
+
start_date: z
|
|
12
|
+
.string()
|
|
13
|
+
.optional()
|
|
14
|
+
.describe("Data de início no formato ISO 8601 (ex: 2026-01-01T00:00:00Z). Necessário apenas quando period='custom'."),
|
|
15
|
+
end_date: z
|
|
16
|
+
.string()
|
|
17
|
+
.optional()
|
|
18
|
+
.describe("Data de fim no formato ISO 8601 (ex: 2026-01-31T23:59:59Z). Necessário apenas quando period='custom'."),
|
|
19
|
+
}, (args) => {
|
|
20
|
+
const period = args['period'] ?? 'last_30_days';
|
|
21
|
+
const startDate = args['start_date'];
|
|
22
|
+
const endDate = args['end_date'];
|
|
23
|
+
let periodDescription;
|
|
24
|
+
let dateInstructions;
|
|
25
|
+
if (period === 'last_7_days') {
|
|
26
|
+
const now = new Date();
|
|
27
|
+
const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
|
|
28
|
+
periodDescription = 'últimos 7 dias';
|
|
29
|
+
dateInstructions = `Use created_after="${weekAgo.toISOString()}" e created_before="${now.toISOString()}" ao chamar list_audit_logs.`;
|
|
30
|
+
}
|
|
31
|
+
else if (period === 'last_30_days') {
|
|
32
|
+
const now = new Date();
|
|
33
|
+
const monthAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
|
|
34
|
+
periodDescription = 'últimos 30 dias';
|
|
35
|
+
dateInstructions = `Use created_after="${monthAgo.toISOString()}" e created_before="${now.toISOString()}" ao chamar list_audit_logs.`;
|
|
36
|
+
}
|
|
37
|
+
else if (period === 'custom' && startDate && endDate) {
|
|
38
|
+
periodDescription = `${startDate} até ${endDate}`;
|
|
39
|
+
dateInstructions = `Use created_after="${startDate}" e created_before="${endDate}" ao chamar list_audit_logs.`;
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
periodDescription = 'período especificado';
|
|
43
|
+
dateInstructions =
|
|
44
|
+
"Peça ao usuário para especificar start_date e end_date quando period='custom'.";
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
messages: [
|
|
48
|
+
{
|
|
49
|
+
role: 'user',
|
|
50
|
+
content: {
|
|
51
|
+
type: 'text',
|
|
52
|
+
text: `Gere um Relatório de Auditoria Certynix completo para o período: ${periodDescription}.
|
|
53
|
+
|
|
54
|
+
## Instruções de execução
|
|
55
|
+
|
|
56
|
+
1. **Chame a tool list_audit_logs** com os seguintes parâmetros:
|
|
57
|
+
- ${dateInstructions}
|
|
58
|
+
- limit: 100
|
|
59
|
+
- Se houver has_more=true na resposta, continue paginando com o next_cursor até obter todos os registros do período.
|
|
60
|
+
|
|
61
|
+
2. **Chame a tool get_trust_score** para incluir o Trust Score atual no relatório.
|
|
62
|
+
|
|
63
|
+
3. **Chame a tool list_alerts** com resolved=false para incluir alertas ativos.
|
|
64
|
+
|
|
65
|
+
## Estrutura do relatório a gerar
|
|
66
|
+
|
|
67
|
+
Após coletar os dados, gere um relatório em Markdown com esta estrutura:
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
# Relatório de Auditoria Certynix
|
|
72
|
+
**Período:** ${periodDescription}
|
|
73
|
+
**Gerado em:** [data atual]
|
|
74
|
+
|
|
75
|
+
## Resumo Executivo
|
|
76
|
+
- Total de ações no período: [N]
|
|
77
|
+
- Trust Score atual: [score]/100
|
|
78
|
+
- Alertas ativos: [N]
|
|
79
|
+
- Eventos críticos: [N]
|
|
80
|
+
|
|
81
|
+
## Trust Score
|
|
82
|
+
- Score: [N]/100 ([label])
|
|
83
|
+
- Identidade: [N]/35
|
|
84
|
+
- Segurança: [N]/25
|
|
85
|
+
- Comportamento: [N]/20
|
|
86
|
+
- Assets: [N]/20
|
|
87
|
+
- Penalidades ativas: [lista ou "Nenhuma"]
|
|
88
|
+
|
|
89
|
+
## Atividade por Tipo de Ação
|
|
90
|
+
| Ação | Quantidade |
|
|
91
|
+
|------|-----------|
|
|
92
|
+
| asset.created | N |
|
|
93
|
+
| api_key.created | N |
|
|
94
|
+
| ... | ... |
|
|
95
|
+
|
|
96
|
+
## Eventos Críticos de Segurança
|
|
97
|
+
[Lista de eventos relacionados a api_key.created, api_key.revoked, member.invited, plan.changed, etc.]
|
|
98
|
+
|
|
99
|
+
## Assets Registrados no Período
|
|
100
|
+
[Sumário de assets registrados: total, status breakdown, first_registrant count]
|
|
101
|
+
|
|
102
|
+
## Alertas de Exposição Ativos
|
|
103
|
+
[Lista de alertas não resolvidos com severidade]
|
|
104
|
+
|
|
105
|
+
## Recomendações
|
|
106
|
+
[Com base nos dados coletados, liste 3-5 recomendações priorizadas]
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
**IMPORTANTE:** Nunca inclua valores de API Keys, tokens, ou outros dados sensíveis no relatório.
|
|
111
|
+
`,
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
],
|
|
115
|
+
};
|
|
116
|
+
});
|
|
117
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt: certynix_security_review
|
|
3
|
+
* Analisa o estado de segurança da Organization e gera recomendações.
|
|
4
|
+
*/
|
|
5
|
+
export function registerSecurityReviewPrompt(server) {
|
|
6
|
+
server.prompt('certynix_security_review', 'Gera uma análise de segurança completa da Organization: Trust Score, penalidades ativas, status de API Keys, alertas abertos e recomendações priorizadas.', {}, (_args) => {
|
|
7
|
+
return {
|
|
8
|
+
messages: [
|
|
9
|
+
{
|
|
10
|
+
role: 'user',
|
|
11
|
+
content: {
|
|
12
|
+
type: 'text',
|
|
13
|
+
text: `Realize uma Revisão de Segurança completa da organização Certynix.
|
|
14
|
+
|
|
15
|
+
## Instruções de execução
|
|
16
|
+
|
|
17
|
+
Execute as seguintes tools em ordem para coletar dados:
|
|
18
|
+
|
|
19
|
+
1. **get_trust_score** — Trust Score atual com componentes e penalidades
|
|
20
|
+
2. **list_alerts** com resolved=false, limit=50 — Alertas de exposição ativos
|
|
21
|
+
3. **list_api_keys** com limit=100 — Inventário de API Keys ativas
|
|
22
|
+
4. **list_audit_logs** com limit=50, action="api_key.created" — Criações recentes de API Keys
|
|
23
|
+
5. **list_audit_logs** com limit=20, action="member.invited" — Membros adicionados recentemente
|
|
24
|
+
6. **list_assets** com limit=20, status="failed" — Assets com falha de verificação
|
|
25
|
+
|
|
26
|
+
## Estrutura da análise a gerar
|
|
27
|
+
|
|
28
|
+
Após coletar todos os dados, gere uma Revisão de Segurança em Markdown:
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
# Revisão de Segurança Certynix
|
|
33
|
+
**Data:** [data atual]
|
|
34
|
+
**Status Geral:** [Critico / Atenção / Bom / Excelente com base no score]
|
|
35
|
+
|
|
36
|
+
## Trust Score: [N]/100
|
|
37
|
+
|
|
38
|
+
### Componentes
|
|
39
|
+
| Pilar | Pontuação | Máximo | Status |
|
|
40
|
+
|-------|-----------|--------|--------|
|
|
41
|
+
| Identidade | N | 35 | [OK/Atenção/Crítico] |
|
|
42
|
+
| Segurança | N | 25 | [OK/Atenção/Crítico] |
|
|
43
|
+
| Comportamento | N | 20 | [OK/Atenção/Crítico] |
|
|
44
|
+
| Assets | N | 20 | [OK/Atenção/Crítico] |
|
|
45
|
+
|
|
46
|
+
### Penalidades Ativas
|
|
47
|
+
[Lista de penalidades ou "Nenhuma penalidade ativa"]
|
|
48
|
+
|
|
49
|
+
## Alertas de Exposição ([N] ativos)
|
|
50
|
+
|
|
51
|
+
### Alta Severidade ([N])
|
|
52
|
+
[Lista de alertas high com descrição]
|
|
53
|
+
|
|
54
|
+
### Média Severidade ([N])
|
|
55
|
+
[Lista de alertas medium]
|
|
56
|
+
|
|
57
|
+
### Baixa Severidade ([N])
|
|
58
|
+
[Lista de alertas low]
|
|
59
|
+
|
|
60
|
+
## API Keys ([N] ativas)
|
|
61
|
+
[Listar todas as API Keys com nome e data de criação]
|
|
62
|
+
[Identificar keys não utilizadas recentemente]
|
|
63
|
+
[Identificar keys criadas há mais de 90 dias sem rotação]
|
|
64
|
+
|
|
65
|
+
## Observações de Acesso
|
|
66
|
+
[Membros adicionados recentemente]
|
|
67
|
+
[API Keys criadas recentemente]
|
|
68
|
+
|
|
69
|
+
## Assets com Falha ([N])
|
|
70
|
+
[Lista de assets com status=failed]
|
|
71
|
+
|
|
72
|
+
## Recomendações Priorizadas
|
|
73
|
+
|
|
74
|
+
### Críticas (ação imediata)
|
|
75
|
+
1. [recomendação baseada nos dados]
|
|
76
|
+
|
|
77
|
+
### Altas (próxima semana)
|
|
78
|
+
1. [recomendação baseada nos dados]
|
|
79
|
+
|
|
80
|
+
### Médias (próximo mês)
|
|
81
|
+
1. [recomendação baseada nos dados]
|
|
82
|
+
|
|
83
|
+
## Score de Maturidade de Segurança
|
|
84
|
+
[Avaliação qualitativa de 1-5 com justificativa baseada nos dados coletados]
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
**IMPORTANTE:** Nunca inclua valores de API Keys, tokens, signing secrets ou outros dados sensíveis na análise.
|
|
89
|
+
`,
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { CertynixClient } from '@certynix/sdk';
|
|
3
|
+
/**
|
|
4
|
+
* Resource: certynix://alerts/active
|
|
5
|
+
* Lista todos os Exposure Alerts ativos não resolvidos.
|
|
6
|
+
*/
|
|
7
|
+
export declare function registerActiveAlertsResource(server: McpServer, client: CertynixClient): void;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { formatError } from '../utils/format.js';
|
|
2
|
+
/**
|
|
3
|
+
* Resource: certynix://alerts/active
|
|
4
|
+
* Lista todos os Exposure Alerts ativos não resolvidos.
|
|
5
|
+
*/
|
|
6
|
+
export function registerActiveAlertsResource(server, client) {
|
|
7
|
+
server.resource('alerts-active', 'certynix://alerts/active', {
|
|
8
|
+
description: 'Lista de Exposure Alerts ativos não resolvidos: anomalias de integridade detectadas automaticamente (surtos de verificação, versões conflitantes, assets não verificados).',
|
|
9
|
+
mimeType: 'application/json',
|
|
10
|
+
}, async (_uri) => {
|
|
11
|
+
try {
|
|
12
|
+
const page = await client.alerts.listPage({ resolved: false, limit: 50 });
|
|
13
|
+
return {
|
|
14
|
+
contents: [
|
|
15
|
+
{
|
|
16
|
+
uri: 'certynix://alerts/active',
|
|
17
|
+
mimeType: 'application/json',
|
|
18
|
+
text: JSON.stringify({
|
|
19
|
+
data: page.data,
|
|
20
|
+
total_active: page.data.length,
|
|
21
|
+
has_more: page.pagination.has_more,
|
|
22
|
+
next_cursor: page.pagination.next_cursor,
|
|
23
|
+
note: page.pagination.has_more
|
|
24
|
+
? 'Use a tool list_alerts com cursor para ver mais alertas.'
|
|
25
|
+
: undefined,
|
|
26
|
+
}, null, 2),
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
return {
|
|
33
|
+
contents: [
|
|
34
|
+
{
|
|
35
|
+
uri: 'certynix://alerts/active',
|
|
36
|
+
mimeType: 'application/json',
|
|
37
|
+
text: JSON.stringify({ error: formatError(err) }, null, 2),
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { CertynixClient } from '@certynix/sdk';
|
|
3
|
+
/**
|
|
4
|
+
* Resource template: certynix://assets/{asset_id}
|
|
5
|
+
* Retorna metadados completos de um asset específico.
|
|
6
|
+
*/
|
|
7
|
+
export declare function registerAssetResource(server: McpServer, client: CertynixClient): void;
|