@purplesquirrel/guardrails-mcp-server 1.0.0 → 1.0.1

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.
Files changed (2) hide show
  1. package/index.js +393 -0
  2. package/package.json +4 -1
package/index.js ADDED
@@ -0,0 +1,393 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * AI Agent Guardrails MCP Server
5
+ * Security layer for Claude Code and AI agents
6
+ *
7
+ * Provides input validation, output filtering, policy enforcement, and audit logging
8
+ */
9
+
10
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
11
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
12
+ import {
13
+ CallToolRequestSchema,
14
+ ListToolsRequestSchema,
15
+ } from "@modelcontextprotocol/sdk/types.js";
16
+
17
+ import { GuardrailsEngine } from './src/engine/GuardrailsEngine.js';
18
+ import { InputValidator } from './src/validators/InputValidator.js';
19
+ import { OutputFilter } from './src/filters/OutputFilter.js';
20
+ import { PolicyEngine } from './src/policies/PolicyEngine.js';
21
+ import { AuditLogger } from './src/audit/AuditLogger.js';
22
+
23
+ // Initialize components
24
+ const config = {
25
+ enableInputValidation: true,
26
+ enableOutputFiltering: true,
27
+ enablePolicyEnforcement: true,
28
+ enableAuditLogging: true,
29
+ enableRateLimiting: true,
30
+ maxRequestsPerMinute: parseInt(process.env.GUARDRAILS_RATE_LIMIT || '60'),
31
+ };
32
+
33
+ const engine = new GuardrailsEngine(config);
34
+ const validator = new InputValidator();
35
+ const filter = new OutputFilter();
36
+ const policyEngine = new PolicyEngine();
37
+ const logger = new AuditLogger({ enableConsoleLog: false });
38
+
39
+ // Create server
40
+ const server = new Server(
41
+ {
42
+ name: "guardrails-mcp-server",
43
+ version: "1.0.1",
44
+ },
45
+ {
46
+ capabilities: {
47
+ tools: {},
48
+ },
49
+ }
50
+ );
51
+
52
+ // Tool definitions
53
+ const tools = [
54
+ {
55
+ name: "validate_input",
56
+ description: "Validate and sanitize user input for prompt injection, malicious patterns, and sensitive data",
57
+ inputSchema: {
58
+ type: "object",
59
+ properties: {
60
+ content: {
61
+ type: "string",
62
+ description: "The input content to validate"
63
+ },
64
+ context: {
65
+ type: "string",
66
+ description: "Optional context about the input source"
67
+ }
68
+ },
69
+ required: ["content"]
70
+ }
71
+ },
72
+ {
73
+ name: "filter_output",
74
+ description: "Filter and redact sensitive information from AI output",
75
+ inputSchema: {
76
+ type: "object",
77
+ properties: {
78
+ content: {
79
+ type: "string",
80
+ description: "The output content to filter"
81
+ },
82
+ redactPII: {
83
+ type: "boolean",
84
+ description: "Whether to redact personally identifiable information",
85
+ default: true
86
+ },
87
+ redactSecrets: {
88
+ type: "boolean",
89
+ description: "Whether to redact secrets and credentials",
90
+ default: true
91
+ }
92
+ },
93
+ required: ["content"]
94
+ }
95
+ },
96
+ {
97
+ name: "check_policy",
98
+ description: "Check if an action is allowed by security policies",
99
+ inputSchema: {
100
+ type: "object",
101
+ properties: {
102
+ action: {
103
+ type: "string",
104
+ description: "The action to check (e.g., 'file_read', 'network_access')"
105
+ },
106
+ resource: {
107
+ type: "string",
108
+ description: "The resource being accessed"
109
+ },
110
+ user: {
111
+ type: "string",
112
+ description: "The user or agent performing the action"
113
+ }
114
+ },
115
+ required: ["action", "resource"]
116
+ }
117
+ },
118
+ {
119
+ name: "get_audit_logs",
120
+ description: "Retrieve audit logs for guardrails events",
121
+ inputSchema: {
122
+ type: "object",
123
+ properties: {
124
+ limit: {
125
+ type: "number",
126
+ description: "Maximum number of logs to return",
127
+ default: 100
128
+ },
129
+ type: {
130
+ type: "string",
131
+ description: "Filter by event type"
132
+ },
133
+ since: {
134
+ type: "string",
135
+ description: "ISO timestamp to filter logs after"
136
+ }
137
+ }
138
+ }
139
+ },
140
+ {
141
+ name: "get_metrics",
142
+ description: "Get guardrails metrics and statistics",
143
+ inputSchema: {
144
+ type: "object",
145
+ properties: {}
146
+ }
147
+ },
148
+ {
149
+ name: "add_policy",
150
+ description: "Add a custom security policy",
151
+ inputSchema: {
152
+ type: "object",
153
+ properties: {
154
+ id: {
155
+ type: "string",
156
+ description: "Unique policy identifier"
157
+ },
158
+ name: {
159
+ type: "string",
160
+ description: "Human-readable policy name"
161
+ },
162
+ description: {
163
+ type: "string",
164
+ description: "Policy description"
165
+ },
166
+ pattern: {
167
+ type: "string",
168
+ description: "Regex pattern to match"
169
+ },
170
+ action: {
171
+ type: "string",
172
+ enum: ["deny", "warn"],
173
+ description: "Action when pattern matches"
174
+ }
175
+ },
176
+ required: ["id", "name", "pattern"]
177
+ }
178
+ },
179
+ {
180
+ name: "add_blocked_pattern",
181
+ description: "Add a pattern to block in inputs",
182
+ inputSchema: {
183
+ type: "object",
184
+ properties: {
185
+ pattern: {
186
+ type: "string",
187
+ description: "Regex pattern to block"
188
+ },
189
+ name: {
190
+ type: "string",
191
+ description: "Name for this pattern"
192
+ },
193
+ severity: {
194
+ type: "string",
195
+ enum: ["low", "medium", "high", "critical"],
196
+ description: "Severity level when pattern is matched"
197
+ }
198
+ },
199
+ required: ["pattern", "name"]
200
+ }
201
+ },
202
+ {
203
+ name: "get_summary",
204
+ description: "Get a summary report of guardrails activity",
205
+ inputSchema: {
206
+ type: "object",
207
+ properties: {
208
+ hours: {
209
+ type: "number",
210
+ description: "Number of hours to include in summary",
211
+ default: 24
212
+ }
213
+ }
214
+ }
215
+ }
216
+ ];
217
+
218
+ // List tools handler
219
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
220
+ return { tools };
221
+ });
222
+
223
+ // Call tool handler
224
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
225
+ const { name, arguments: args } = request.params;
226
+
227
+ try {
228
+ switch (name) {
229
+ case "validate_input": {
230
+ const result = await validator.validate(args.content, { source: args.context });
231
+ await logger.log({
232
+ type: result.valid ? 'INPUT_VALIDATED' : 'INPUT_VALIDATION_FAILED',
233
+ input: args.content?.substring(0, 100),
234
+ violations: result.violations
235
+ });
236
+ return {
237
+ content: [{
238
+ type: "text",
239
+ text: JSON.stringify({
240
+ isValid: result.valid,
241
+ issues: result.violations,
242
+ stats: result.stats
243
+ }, null, 2)
244
+ }]
245
+ };
246
+ }
247
+
248
+ case "filter_output": {
249
+ const result = await filter.filter(args.content, {
250
+ redactPII: args.redactPII !== false,
251
+ redactSecrets: args.redactSecrets !== false
252
+ });
253
+ await logger.log({
254
+ type: 'OUTPUT_FILTERED',
255
+ redactionsApplied: result.redactions?.length || 0
256
+ });
257
+ return {
258
+ content: [{
259
+ type: "text",
260
+ text: JSON.stringify({
261
+ filtered: result.response,
262
+ modified: result.modified,
263
+ blocked: result.blocked,
264
+ redactions: result.redactions
265
+ }, null, 2)
266
+ }]
267
+ };
268
+ }
269
+
270
+ case "check_policy": {
271
+ const result = await policyEngine.evaluate({
272
+ name: args.action,
273
+ resource: args.resource
274
+ }, {
275
+ userId: args.user || 'anonymous'
276
+ });
277
+ await logger.log({
278
+ type: result.allowed ? 'POLICY_CHECK_PASSED' : 'POLICY_VIOLATION',
279
+ action: args.action,
280
+ resource: args.resource,
281
+ allowed: result.allowed,
282
+ policy: result.violatedPolicy
283
+ });
284
+ return {
285
+ content: [{
286
+ type: "text",
287
+ text: JSON.stringify(result, null, 2)
288
+ }]
289
+ };
290
+ }
291
+
292
+ case "get_audit_logs": {
293
+ const logs = logger.getLogs({
294
+ limit: args.limit || 100,
295
+ type: args.type,
296
+ startTime: args.since
297
+ });
298
+ return {
299
+ content: [{
300
+ type: "text",
301
+ text: JSON.stringify(logs, null, 2)
302
+ }]
303
+ };
304
+ }
305
+
306
+ case "get_metrics": {
307
+ const metrics = logger.getMetrics();
308
+ return {
309
+ content: [{
310
+ type: "text",
311
+ text: JSON.stringify(metrics, null, 2)
312
+ }]
313
+ };
314
+ }
315
+
316
+ case "add_policy": {
317
+ policyEngine.createSimplePolicy({
318
+ id: args.id,
319
+ name: args.name,
320
+ description: args.description || '',
321
+ pattern: args.pattern,
322
+ action: args.action || 'deny',
323
+ message: `Policy ${args.name} violated`
324
+ });
325
+ await logger.log({
326
+ type: 'POLICY_ADDED',
327
+ policyId: args.id,
328
+ policyName: args.name
329
+ });
330
+ return {
331
+ content: [{
332
+ type: "text",
333
+ text: JSON.stringify({ success: true, message: `Policy '${args.name}' added` })
334
+ }]
335
+ };
336
+ }
337
+
338
+ case "add_blocked_pattern": {
339
+ validator.addInjectionPattern(args.pattern);
340
+ await logger.log({
341
+ type: 'PATTERN_ADDED',
342
+ patternName: args.name,
343
+ severity: args.severity || 'medium'
344
+ });
345
+ return {
346
+ content: [{
347
+ type: "text",
348
+ text: JSON.stringify({ success: true, message: `Pattern '${args.name}' added to blocked list` })
349
+ }]
350
+ };
351
+ }
352
+
353
+ case "get_summary": {
354
+ const summary = logger.getSummary(args.hours || 24);
355
+ return {
356
+ content: [{
357
+ type: "text",
358
+ text: JSON.stringify(summary, null, 2)
359
+ }]
360
+ };
361
+ }
362
+
363
+ default:
364
+ throw new Error(`Unknown tool: ${name}`);
365
+ }
366
+ } catch (error) {
367
+ await logger.log({
368
+ type: 'ERROR',
369
+ level: 'error',
370
+ tool: name,
371
+ error: error.message
372
+ });
373
+ return {
374
+ content: [{
375
+ type: "text",
376
+ text: JSON.stringify({ error: error.message })
377
+ }],
378
+ isError: true
379
+ };
380
+ }
381
+ });
382
+
383
+ // Start server
384
+ async function main() {
385
+ const transport = new StdioServerTransport();
386
+ await server.connect(transport);
387
+ console.error("Guardrails MCP Server running on stdio");
388
+ }
389
+
390
+ main().catch((error) => {
391
+ console.error("Fatal error:", error);
392
+ process.exit(1);
393
+ });
package/package.json CHANGED
@@ -1,9 +1,12 @@
1
1
  {
2
2
  "name": "@purplesquirrel/guardrails-mcp-server",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "AI Agent Guardrails MCP Server - Security layer for Claude Code and AI agents",
5
5
  "main": "index.js",
6
6
  "type": "module",
7
+ "bin": {
8
+ "guardrails-mcp-server": "./index.js"
9
+ },
7
10
  "scripts": {
8
11
  "start": "node index.js",
9
12
  "test": "node --test tests/",