@promptguardapp/mcp 0.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Krish Ojha
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,86 @@
1
+ # PromptGuard
2
+
3
+ > A local-first Model Context Protocol (MCP) server that scans developer prompts for secrets, personally identifiable information, and cost before they reach the language model. Includes prompt compression and structural feedback.
4
+
5
+ ## What it does
6
+
7
+ PromptGuard plugs into Claude Desktop (or any MCP-compatible client) and exposes four tools:
8
+
9
+ - `scan_prompt`: detects 22 patterns of sensitive data including AWS keys, GitHub tokens, OpenAI / Anthropic / Stripe / Slack keys, credit cards (Luhn validated), US SSNs, Indian Aadhaar (Verhoeff validated), PAN, GSTIN, UPI handles, IFSC codes, emails, and phone numbers. Sub-millisecond scans, with per-finding explanations.
10
+ - `optimize_prompt`: suggests a cleaner version of a prompt with structural feedback (missing task verb, missing output format). Stays silent on already-good prompts.
11
+ - `compress_prompt`: aggressive token reduction with three levels (light, medium, aggressive). Preserves code blocks. Realistic 10 to 25 percent savings on typical prompts.
12
+ - `estimate_cost`: token count and dollar estimate across Claude (Opus, Sonnet, Haiku) and OpenAI (GPT-4o, GPT-4o-mini). Uses the correct tokenizer per model (o200k_base for GPT-4o, cl100k_base for older OpenAI and as an approximation for Claude).
13
+
14
+ All analysis runs on the user's machine. No prompt content is transmitted to external services.
15
+
16
+ ## Installation
17
+
18
+ The simplest setup uses `npx`, no manual install required. Add this block to Claude Desktop's MCP config at `~/Library/Application Support/Claude/claude_desktop_config.json` (create the file if it does not exist):
19
+
20
+ ```json
21
+ {
22
+ "mcpServers": {
23
+ "promptguard": {
24
+ "command": "npx",
25
+ "args": ["-y", "@promptguardapp/mcp"]
26
+ }
27
+ }
28
+ }
29
+ ```
30
+
31
+ Restart Claude Desktop. The PromptGuard tools become available immediately.
32
+
33
+ If `node` or `npx` are not on Claude Desktop's PATH (common when Node is installed via nvm), use the absolute path:
34
+
35
+ ```json
36
+ {
37
+ "mcpServers": {
38
+ "promptguard": {
39
+ "command": "/absolute/path/to/npx",
40
+ "args": ["-y", "@promptguardapp/mcp"]
41
+ }
42
+ }
43
+ }
44
+ ```
45
+
46
+ To find your npx path, run `which npx` in a terminal.
47
+
48
+ ## Usage in Claude
49
+
50
+ Ask Claude to use any of the tools by name. For example:
51
+
52
+ - "Use the scan_prompt tool on this text: ..."
53
+ - "Use compress_prompt on this prompt at aggressive level."
54
+ - "Use estimate_cost to compare gpt-4o-mini and claude-sonnet-4-6 for this prompt."
55
+
56
+ Claude will call the appropriate tool and present the result.
57
+
58
+ ## Requirements
59
+
60
+ - Node.js 20 or later
61
+ - Claude Desktop, or any other MCP-compatible client
62
+
63
+ ## Development
64
+
65
+ Clone the repository if you want to contribute or run from source:
66
+
67
+ ```bash
68
+ git clone https://github.com/KrishOjha1810/promptguard-mcp.git
69
+ cd promptguard-mcp
70
+ npm install
71
+ npm run build
72
+ npm test
73
+ ```
74
+
75
+ Scripts available:
76
+
77
+ ```bash
78
+ npm run dev # Run from source via tsx
79
+ npm run build # Compile to dist/
80
+ npm run test # Run the test suite
81
+ npm run typecheck # Type check without emitting
82
+ ```
83
+
84
+ ## License
85
+
86
+ MIT. See [LICENSE](./LICENSE) for the full text.
Binary file
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compress.js","sourceRoot":"","sources":["../src/compress.ts"],"names":[],"mappings":"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"}
package/dist/cost.js ADDED
@@ -0,0 +1,71 @@
1
+ import { getEncoding } from "js-tiktoken";
2
+ // GPT-4o family uses o200k_base, an updated tokenizer that produces different
3
+ // token counts than cl100k_base for the same text. Claude models do not expose
4
+ // their tokenizer; cl100k_base is a close approximation flagged below.
5
+ const ENCODING_BY_MODEL = {
6
+ "claude-opus-4-7": "cl100k_base",
7
+ "claude-sonnet-4-6": "cl100k_base",
8
+ "claude-haiku-4-5": "cl100k_base",
9
+ "gpt-4o": "o200k_base",
10
+ "gpt-4o-mini": "o200k_base",
11
+ };
12
+ // USD per 1,000,000 tokens. Update as model pricing changes.
13
+ const PRICING = {
14
+ "claude-opus-4-7": { input: 15, output: 75 },
15
+ "claude-sonnet-4-6": { input: 3, output: 15 },
16
+ "claude-haiku-4-5": { input: 0.8, output: 4 },
17
+ "gpt-4o": { input: 2.5, output: 10 },
18
+ "gpt-4o-mini": { input: 0.15, output: 0.6 },
19
+ };
20
+ const PRICING_LAST_UPDATED = "2026-05-23";
21
+ const _encodings = new Map();
22
+ function getEnc(name) {
23
+ const cached = _encodings.get(name);
24
+ if (cached)
25
+ return cached;
26
+ const fresh = getEncoding(name);
27
+ _encodings.set(name, fresh);
28
+ return fresh;
29
+ }
30
+ /**
31
+ * Count tokens for a piece of text. If a model is given, the tokenizer that
32
+ * matches that model is used (exact for OpenAI, approximate for Claude). If
33
+ * not given, cl100k_base is used as a sensible default for generic comparisons.
34
+ */
35
+ export function countTokens(text, model) {
36
+ const encoding = model
37
+ ? ENCODING_BY_MODEL[model]
38
+ : "cl100k_base";
39
+ return getEnc(encoding).encode(text).length;
40
+ }
41
+ export function estimateCost(text, model, expectedOutputTokens) {
42
+ const inputTokens = countTokens(text, model);
43
+ const outputTokens = expectedOutputTokens !== undefined
44
+ ? expectedOutputTokens
45
+ : Math.min(inputTokens, 1024);
46
+ const price = PRICING[model];
47
+ const inputCost = (inputTokens / 1_000_000) * price.input;
48
+ const outputCost = (outputTokens / 1_000_000) * price.output;
49
+ return {
50
+ model,
51
+ inputTokens,
52
+ estimatedOutputTokens: outputTokens,
53
+ inputCostUsd: round(inputCost, 6),
54
+ estimatedOutputCostUsd: round(outputCost, 6),
55
+ totalEstimatedUsd: round(inputCost + outputCost, 6),
56
+ approximate: model.startsWith("claude-"),
57
+ pricingLastUpdated: PRICING_LAST_UPDATED,
58
+ };
59
+ }
60
+ function round(n, decimals) {
61
+ const factor = Math.pow(10, decimals);
62
+ return Math.round(n * factor) / factor;
63
+ }
64
+ export const SUPPORTED_MODELS = [
65
+ "claude-opus-4-7",
66
+ "claude-sonnet-4-6",
67
+ "claude-haiku-4-5",
68
+ "gpt-4o",
69
+ "gpt-4o-mini",
70
+ ];
71
+ //# sourceMappingURL=cost.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost.js","sourceRoot":"","sources":["../src/cost.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,159 @@
1
+ export function luhnCheck(input) {
2
+ const digits = input.replace(/[\s-]/g, "");
3
+ if (digits.length < 13 || digits.length > 19)
4
+ return false;
5
+ if (!/^\d+$/.test(digits))
6
+ return false;
7
+ let sum = 0;
8
+ let alternate = false;
9
+ for (let i = digits.length - 1; i >= 0; i--) {
10
+ let n = parseInt(digits[i], 10);
11
+ if (alternate) {
12
+ n *= 2;
13
+ if (n > 9)
14
+ n = (n % 10) + 1;
15
+ }
16
+ sum += n;
17
+ alternate = !alternate;
18
+ }
19
+ return sum % 10 === 0;
20
+ }
21
+ // Verhoeff checksum algorithm. Used by Aadhaar numbers to detect typos.
22
+ const VERHOEFF_D = [
23
+ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
24
+ [1, 2, 3, 4, 0, 6, 7, 8, 9, 5],
25
+ [2, 3, 4, 0, 1, 7, 8, 9, 5, 6],
26
+ [3, 4, 0, 1, 2, 8, 9, 5, 6, 7],
27
+ [4, 0, 1, 2, 3, 9, 5, 6, 7, 8],
28
+ [5, 9, 8, 7, 6, 0, 4, 3, 2, 1],
29
+ [6, 5, 9, 8, 7, 1, 0, 4, 3, 2],
30
+ [7, 6, 5, 9, 8, 2, 1, 0, 4, 3],
31
+ [8, 7, 6, 5, 9, 3, 2, 1, 0, 4],
32
+ [9, 8, 7, 6, 5, 4, 3, 2, 1, 0],
33
+ ];
34
+ const VERHOEFF_P = [
35
+ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
36
+ [1, 5, 7, 6, 2, 8, 3, 0, 9, 4],
37
+ [5, 8, 0, 3, 7, 9, 6, 1, 4, 2],
38
+ [8, 9, 1, 6, 0, 4, 3, 5, 2, 7],
39
+ [9, 4, 5, 3, 1, 2, 6, 8, 7, 0],
40
+ [4, 2, 8, 6, 5, 7, 3, 9, 0, 1],
41
+ [2, 7, 9, 3, 8, 0, 6, 4, 1, 5],
42
+ [7, 0, 4, 6, 9, 1, 3, 2, 5, 8],
43
+ ];
44
+ export function verhoeffCheck(input) {
45
+ const digits = input.replace(/[\s-]/g, "");
46
+ if (digits.length !== 12)
47
+ return false;
48
+ if (!/^[2-9]\d{11}$/.test(digits))
49
+ return false;
50
+ let c = 0;
51
+ const reversed = digits.split("").reverse();
52
+ for (let i = 0; i < reversed.length; i++) {
53
+ const digit = parseInt(reversed[i], 10);
54
+ c = VERHOEFF_D[c][VERHOEFF_P[i % 8][digit]];
55
+ }
56
+ return c === 0;
57
+ }
58
+ export const PII_RULES = [
59
+ // --------------------------------------------------------------------
60
+ // Universal PII
61
+ // --------------------------------------------------------------------
62
+ {
63
+ id: "email_address",
64
+ name: "Email Address",
65
+ pattern: /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g,
66
+ severity: "medium",
67
+ confidence: 0.85,
68
+ explanation: "Email address detected. Sharing real user or customer emails in prompts is a privacy risk.",
69
+ },
70
+ {
71
+ id: "credit_card",
72
+ name: "Credit Card Number",
73
+ pattern: /\b(?:\d[ -]?){13,19}\b/g,
74
+ severity: "critical",
75
+ confidence: 0.9,
76
+ explanation: "Credit card number (Luhn-validated). Sharing card numbers in prompts violates PCI compliance and exposes the cardholder.",
77
+ validator: luhnCheck,
78
+ },
79
+ // --------------------------------------------------------------------
80
+ // US-specific PII
81
+ // --------------------------------------------------------------------
82
+ {
83
+ id: "us_phone_number",
84
+ name: "US Phone Number",
85
+ pattern: /\b(?:\+?1[-.\s]?)?\(?[2-9]\d{2}\)?[-.\s]\d{3}[-.\s]\d{4}\b/g,
86
+ severity: "medium",
87
+ confidence: 0.75,
88
+ explanation: "US phone number detected. May identify an individual customer or employee.",
89
+ },
90
+ {
91
+ id: "us_ssn",
92
+ name: "US Social Security Number",
93
+ pattern: /\b(?!000|666|9\d{2})\d{3}-(?!00)\d{2}-(?!0000)\d{4}\b/g,
94
+ severity: "critical",
95
+ confidence: 0.9,
96
+ explanation: "US social security number detected. Sharing SSNs in prompts is a serious privacy and regulatory risk.",
97
+ },
98
+ // --------------------------------------------------------------------
99
+ // India-specific PII
100
+ // --------------------------------------------------------------------
101
+ {
102
+ id: "india_mobile_number",
103
+ name: "Indian Mobile Number",
104
+ // 10-digit number starting 6-9, optionally prefixed with +91 / 91 / 0,
105
+ // optionally split as 5+5 with a hyphen or space.
106
+ pattern: /\b(?:(?:\+|00)?91[-.\s]?)?[6-9]\d{4}[-.\s]?\d{5}\b/g,
107
+ severity: "medium",
108
+ confidence: 0.75,
109
+ explanation: "Indian mobile number detected. May identify an individual customer or employee.",
110
+ },
111
+ {
112
+ id: "india_aadhaar",
113
+ name: "Aadhaar Number",
114
+ // 12 digits starting 2-9, optionally split as 4-4-4 with spaces or hyphens.
115
+ // Verhoeff checksum applied as a validator below.
116
+ pattern: /\b[2-9]\d{3}[-\s]?\d{4}[-\s]?\d{4}\b/g,
117
+ severity: "critical",
118
+ confidence: 0.95,
119
+ explanation: "Aadhaar number (Verhoeff-validated). Sharing Aadhaar is a serious privacy and regulatory risk under Indian data protection law.",
120
+ validator: verhoeffCheck,
121
+ },
122
+ {
123
+ id: "india_pan",
124
+ name: "Indian PAN (Permanent Account Number)",
125
+ // 5 letters + 4 digits + 1 letter (e.g. ABCDE1234F).
126
+ pattern: /\b[A-Z]{5}\d{4}[A-Z]\b/g,
127
+ severity: "high",
128
+ confidence: 0.85,
129
+ explanation: "Indian PAN detected. The PAN is the primary tax identifier in India and should not appear in prompts.",
130
+ },
131
+ {
132
+ id: "india_gstin",
133
+ name: "Indian GSTIN",
134
+ // 2 digit state code + 10 char PAN + entity digit + Z + checksum char.
135
+ pattern: /\b\d{2}[A-Z]{5}\d{4}[A-Z]\dZ[0-9A-Z]\b/g,
136
+ severity: "medium",
137
+ confidence: 0.9,
138
+ explanation: "Indian GSTIN detected. While less sensitive than PAN, this can link a business or proprietor to filings.",
139
+ },
140
+ {
141
+ id: "india_upi_id",
142
+ name: "Indian UPI ID",
143
+ // username@handle where the handle has no dot, distinguishing it from email.
144
+ pattern: /\b[A-Za-z0-9._-]+@[a-z]{2,20}\b(?!\.)/g,
145
+ severity: "high",
146
+ confidence: 0.85,
147
+ explanation: "Indian UPI ID detected. UPI handles link directly to bank accounts and payment flows.",
148
+ },
149
+ {
150
+ id: "india_ifsc",
151
+ name: "Indian IFSC Code",
152
+ // 4 letters (bank code) + '0' + 6 alphanumeric (branch code).
153
+ pattern: /\b[A-Z]{4}0[A-Z0-9]{6}\b/g,
154
+ severity: "medium",
155
+ confidence: 0.9,
156
+ explanation: "Indian IFSC code detected. Identifies a specific bank branch, sensitive when combined with an account number.",
157
+ },
158
+ ];
159
+ //# sourceMappingURL=pii-rules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pii-rules.js","sourceRoot":"","sources":["../../src/detectors/pii-rules.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC3C,IAAI,MAAM,CAAC,MAAM,GAAG,EAAE,IAAI,MAAM,CAAC,MAAM,GAAG,EAAE;QAAE,OAAO,KAAK,CAAC;IAC3D,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAC;IAExC,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,KAAK,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5C,IAAI,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAChC,IAAI,SAAS,EAAE,CAAC;YACd,CAAC,IAAI,CAAC,CAAC;YACP,IAAI,CAAC,GAAG,CAAC;gBAAE,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;QAC9B,CAAC;QACD,GAAG,IAAI,CAAC,CAAC;QACT,SAAS,GAAG,CAAC,SAAS,CAAC;IACzB,CAAC;IACD,OAAO,GAAG,GAAG,EAAE,KAAK,CAAC,CAAC;AACxB,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,GAAG;IACjB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;CAC/B,CAAC;AAEF,MAAM,UAAU,GAAG;IACjB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,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"}
@@ -0,0 +1,99 @@
1
+ export const SECRET_RULES = [
2
+ {
3
+ id: "aws_access_key_id",
4
+ name: "AWS Access Key ID",
5
+ pattern: /\b(AKIA|ABIA|ACCA|AGPA|AIDA|AIPA|ANPA|ANVA|AROA|APKA|ASCA|ASIA)[0-9A-Z]{16}\b/g,
6
+ severity: "critical",
7
+ confidence: 0.95,
8
+ explanation: "AWS access key identifier. Grants programmatic access to AWS resources and should not appear in prompts.",
9
+ },
10
+ {
11
+ id: "github_pat_classic",
12
+ name: "GitHub Personal Access Token (classic)",
13
+ pattern: /\bghp_[A-Za-z0-9]{36}\b/g,
14
+ severity: "critical",
15
+ confidence: 0.99,
16
+ explanation: "GitHub classic personal access token. Grants repository and API access tied to the issuing user.",
17
+ },
18
+ {
19
+ id: "github_pat_fine_grained",
20
+ name: "GitHub Fine-grained Personal Access Token",
21
+ pattern: /\bgithub_pat_[A-Za-z0-9_]{82}\b/g,
22
+ severity: "critical",
23
+ confidence: 0.99,
24
+ explanation: "GitHub fine-grained personal access token. Grants scoped API access tied to the issuing user.",
25
+ },
26
+ {
27
+ id: "github_oauth_token",
28
+ name: "GitHub OAuth Access Token",
29
+ pattern: /\bgho_[A-Za-z0-9]{36}\b/g,
30
+ severity: "critical",
31
+ confidence: 0.99,
32
+ explanation: "GitHub OAuth access token. Grants user-level API access through an OAuth application.",
33
+ },
34
+ {
35
+ id: "openai_api_key",
36
+ name: "OpenAI API Key",
37
+ pattern: /\bsk-[A-Za-z0-9]{20}T3BlbkFJ[A-Za-z0-9]{20}\b|\bsk-proj-[A-Za-z0-9_-]{74,}\b|\bsk-svcacct-[A-Za-z0-9_-]{40,}\b/g,
38
+ severity: "critical",
39
+ confidence: 0.95,
40
+ explanation: "OpenAI API key. Authorizes access to an OpenAI account and incurs billing on use.",
41
+ },
42
+ {
43
+ id: "anthropic_api_key",
44
+ name: "Anthropic API Key",
45
+ pattern: /\bsk-ant-api03-[A-Za-z0-9_-]{93}AA\b/g,
46
+ severity: "critical",
47
+ confidence: 0.99,
48
+ explanation: "Anthropic API key. Authorizes access to an Anthropic account and incurs billing on use.",
49
+ },
50
+ {
51
+ id: "stripe_live_secret_key",
52
+ name: "Stripe Live Secret Key",
53
+ pattern: /\b(?:sk|rk)_live_[A-Za-z0-9]{24,}\b/g,
54
+ severity: "critical",
55
+ confidence: 0.99,
56
+ explanation: "Stripe live secret key. Authorizes charges and refunds against live customer accounts.",
57
+ },
58
+ {
59
+ id: "stripe_test_secret_key",
60
+ name: "Stripe Test Secret Key",
61
+ pattern: /\b(?:sk|rk)_test_[A-Za-z0-9]{24,}\b/g,
62
+ severity: "high",
63
+ confidence: 0.99,
64
+ explanation: "Stripe test secret key. Sandbox use only, but should still be kept private.",
65
+ },
66
+ {
67
+ id: "slack_bot_token",
68
+ name: "Slack Bot Token",
69
+ pattern: /\bxoxb-[0-9]{10,13}-[0-9]{10,13}-[A-Za-z0-9]{24}\b/g,
70
+ severity: "high",
71
+ confidence: 0.95,
72
+ explanation: "Slack bot token. Grants access to a Slack workspace as a bot identity.",
73
+ },
74
+ {
75
+ id: "slack_user_token",
76
+ name: "Slack User Token",
77
+ pattern: /\bxoxp-[0-9]{10,13}-[0-9]{10,13}-[0-9]{10,13}-[A-Za-z0-9]{32}\b/g,
78
+ severity: "high",
79
+ confidence: 0.95,
80
+ explanation: "Slack user token. Grants access to a Slack workspace as a specific user.",
81
+ },
82
+ {
83
+ id: "google_api_key",
84
+ name: "Google API Key",
85
+ pattern: /\bAIza[0-9A-Za-z_-]{35}\b/g,
86
+ severity: "high",
87
+ confidence: 0.9,
88
+ explanation: "Google API key. Used for Google Cloud and Google Workspace APIs.",
89
+ },
90
+ {
91
+ id: "pem_private_key",
92
+ name: "PEM-encoded Private Key",
93
+ pattern: /-----BEGIN(?: [A-Z]+)? PRIVATE KEY-----/g,
94
+ severity: "critical",
95
+ confidence: 0.99,
96
+ explanation: "Private key in PEM format. Private keys must never be shared or transmitted.",
97
+ },
98
+ ];
99
+ //# sourceMappingURL=rules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rules.js","sourceRoot":"","sources":["../../src/detectors/rules.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,YAAY,GAAW;IAClC;QACE,EAAE,EAAE,mBAAmB;QACvB,IAAI,EAAE,mBAAmB;QACzB,OAAO,EACL,gFAAgF;QAClF,QAAQ,EAAE,UAAU;QACpB,UAAU,EAAE,IAAI;QAChB,WAAW,EACT,0GAA0G;KAC7G;IACD;QACE,EAAE,EAAE,oBAAoB;QACxB,IAAI,EAAE,wCAAwC;QAC9C,OAAO,EAAE,0BAA0B;QACnC,QAAQ,EAAE,UAAU;QACpB,UAAU,EAAE,IAAI;QAChB,WAAW,EACT,kGAAkG;KACrG;IACD;QACE,EAAE,EAAE,yBAAyB;QAC7B,IAAI,EAAE,2CAA2C;QACjD,OAAO,EAAE,kCAAkC;QAC3C,QAAQ,EAAE,UAAU;QACpB,UAAU,EAAE,IAAI;QAChB,WAAW,EACT,+FAA+F;KAClG;IACD;QACE,EAAE,EAAE,oBAAoB;QACxB,IAAI,EAAE,2BAA2B;QACjC,OAAO,EAAE,0BAA0B;QACnC,QAAQ,EAAE,UAAU;QACpB,UAAU,EAAE,IAAI;QAChB,WAAW,EACT,uFAAuF;KAC1F;IACD;QACE,EAAE,EAAE,gBAAgB;QACpB,IAAI,EAAE,gBAAgB;QACtB,OAAO,EACL,iHAAiH;QACnH,QAAQ,EAAE,UAAU;QACpB,UAAU,EAAE,IAAI;QAChB,WAAW,EACT,mFAAmF;KACtF;IACD;QACE,EAAE,EAAE,mBAAmB;QACvB,IAAI,EAAE,mBAAmB;QACzB,OAAO,EAAE,uCAAuC;QAChD,QAAQ,EAAE,UAAU;QACpB,UAAU,EAAE,IAAI;QAChB,WAAW,EACT,yFAAyF;KAC5F;IACD;QACE,EAAE,EAAE,wBAAwB;QAC5B,IAAI,EAAE,wBAAwB;QAC9B,OAAO,EAAE,sCAAsC;QAC/C,QAAQ,EAAE,UAAU;QACpB,UAAU,EAAE,IAAI;QAChB,WAAW,EACT,wFAAwF;KAC3F;IACD;QACE,EAAE,EAAE,wBAAwB;QAC5B,IAAI,EAAE,wBAAwB;QAC9B,OAAO,EAAE,sCAAsC;QAC/C,QAAQ,EAAE,MAAM;QAChB,UAAU,EAAE,IAAI;QAChB,WAAW,EACT,6EAA6E;KAChF;IACD;QACE,EAAE,EAAE,iBAAiB;QACrB,IAAI,EAAE,iBAAiB;QACvB,OAAO,EAAE,qDAAqD;QAC9D,QAAQ,EAAE,MAAM;QAChB,UAAU,EAAE,IAAI;QAChB,WAAW,EACT,wEAAwE;KAC3E;IACD;QACE,EAAE,EAAE,kBAAkB;QACtB,IAAI,EAAE,kBAAkB;QACxB,OAAO,EAAE,kEAAkE;QAC3E,QAAQ,EAAE,MAAM;QAChB,UAAU,EAAE,IAAI;QAChB,WAAW,EACT,0EAA0E;KAC7E;IACD;QACE,EAAE,EAAE,gBAAgB;QACpB,IAAI,EAAE,gBAAgB;QACtB,OAAO,EAAE,4BAA4B;QACrC,QAAQ,EAAE,MAAM;QAChB,UAAU,EAAE,GAAG;QACf,WAAW,EACT,kEAAkE;KACrE;IACD;QACE,EAAE,EAAE,iBAAiB;QACrB,IAAI,EAAE,yBAAyB;QAC/B,OAAO,EAAE,0CAA0C;QACnD,QAAQ,EAAE,UAAU;QACpB,UAAU,EAAE,IAAI;QAChB,WAAW,EACT,8EAA8E;KACjF;CACF,CAAC"}
@@ -0,0 +1,49 @@
1
+ import { SECRET_RULES } from "./rules.js";
2
+ import { PII_RULES } from "./pii-rules.js";
3
+ const ALL_RULES = [...SECRET_RULES, ...PII_RULES];
4
+ export function scanText(text) {
5
+ const start = performance.now();
6
+ const findings = [];
7
+ for (const rule of ALL_RULES) {
8
+ rule.pattern.lastIndex = 0;
9
+ let match;
10
+ while ((match = rule.pattern.exec(text)) !== null) {
11
+ const matched = match[0];
12
+ if (rule.validator && !rule.validator(matched))
13
+ continue;
14
+ findings.push({
15
+ type: rule.id,
16
+ rule: rule.name,
17
+ severity: rule.severity,
18
+ start: match.index,
19
+ end: match.index + matched.length,
20
+ matched,
21
+ confidence: rule.confidence,
22
+ explanation: rule.explanation,
23
+ });
24
+ }
25
+ }
26
+ findings.sort((a, b) => a.start - b.start);
27
+ const redactedText = buildRedactedText(text, findings);
28
+ return {
29
+ findings,
30
+ redactedText,
31
+ scanMs: performance.now() - start,
32
+ rulesRun: ALL_RULES.length,
33
+ };
34
+ }
35
+ // Backwards-compatible alias. Older callers used this name.
36
+ export const scanForSecrets = scanText;
37
+ function buildRedactedText(text, findings) {
38
+ if (findings.length === 0)
39
+ return text;
40
+ let result = text;
41
+ const sorted = [...findings].sort((a, b) => b.start - a.start);
42
+ for (const finding of sorted) {
43
+ const marker = `[REDACTED:${finding.type}]`;
44
+ result =
45
+ result.slice(0, finding.start) + marker + result.slice(finding.end);
46
+ }
47
+ return result;
48
+ }
49
+ //# sourceMappingURL=secrets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../src/detectors/secrets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAG3C,MAAM,SAAS,GAAW,CAAC,GAAG,YAAY,EAAE,GAAG,SAAS,CAAC,CAAC;AAE1D,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IAChC,MAAM,QAAQ,GAAc,EAAE,CAAC;IAE/B,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,IAAI,CAAC,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC;QAC3B,IAAI,KAA6B,CAAC;QAClC,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAClD,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACzB,IAAI,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;gBAAE,SAAS;YACzD,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,IAAI,CAAC,EAAE;gBACb,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,GAAG,EAAE,KAAK,CAAC,KAAK,GAAG,OAAO,CAAC,MAAM;gBACjC,OAAO;gBACP,UAAU,EAAE,IAAI,CAAC,UAAU;gBAC3B,WAAW,EAAE,IAAI,CAAC,WAAW;aAC9B,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IAE3C,MAAM,YAAY,GAAG,iBAAiB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAEvD,OAAO;QACL,QAAQ;QACR,YAAY;QACZ,MAAM,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK;QACjC,QAAQ,EAAE,SAAS,CAAC,MAAM;KAC3B,CAAC;AACJ,CAAC;AAED,4DAA4D;AAC5D,MAAM,CAAC,MAAM,cAAc,GAAG,QAAQ,CAAC;AAEvC,SAAS,iBAAiB,CAAC,IAAY,EAAE,QAAmB;IAC1D,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEvC,IAAI,MAAM,GAAG,IAAI,CAAC;IAClB,MAAM,MAAM,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IAC/D,KAAK,MAAM,OAAO,IAAI,MAAM,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,aAAa,OAAO,CAAC,IAAI,GAAG,CAAC;QAC5C,MAAM;YACJ,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,256 @@
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 { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
5
+ import { scanText } from "./detectors/secrets.js";
6
+ import { estimateCost, SUPPORTED_MODELS, } from "./cost.js";
7
+ import { optimizePrompt } from "./optimize.js";
8
+ import { compressPrompt } from "./compress.js";
9
+ const PROMPTGUARD_VERSION = "0.0.1";
10
+ const server = new Server({
11
+ name: "promptguard",
12
+ version: PROMPTGUARD_VERSION,
13
+ }, {
14
+ capabilities: {
15
+ tools: {},
16
+ },
17
+ });
18
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
19
+ tools: [
20
+ {
21
+ name: "ping",
22
+ description: "Hello-world tool that confirms the PromptGuard MCP server is alive. Returns 'pong' with the server version.",
23
+ inputSchema: {
24
+ type: "object",
25
+ properties: {},
26
+ },
27
+ },
28
+ {
29
+ name: "scan_prompt",
30
+ description: "Scan a prompt for secrets, API keys, credentials, and personally identifiable information (emails, phone numbers, credit cards, SSNs) before it is sent to the language model. Returns findings with location, severity, and a human-readable explanation, plus an optional redacted version of the input.",
31
+ inputSchema: {
32
+ type: "object",
33
+ properties: {
34
+ text: {
35
+ type: "string",
36
+ description: "The prompt text to scan.",
37
+ },
38
+ mode: {
39
+ type: "string",
40
+ enum: ["warn", "redact"],
41
+ description: "Return raw matches (warn) or replace each finding with a placeholder (redact). Defaults to warn.",
42
+ },
43
+ },
44
+ required: ["text"],
45
+ },
46
+ },
47
+ {
48
+ name: "optimize_prompt",
49
+ description: "Suggest a tightened version of a prompt by removing filler, verbose phrases, and hedging, and by flagging missing structure such as no task verb or no output format. Stays silent (shouldSuggest:false) on prompts that are already concise. Returns the original and the suggested rewrite side by side along with estimated token savings.",
50
+ inputSchema: {
51
+ type: "object",
52
+ properties: {
53
+ text: {
54
+ type: "string",
55
+ description: "The prompt text to optimize.",
56
+ },
57
+ },
58
+ required: ["text"],
59
+ },
60
+ },
61
+ {
62
+ name: "compress_prompt",
63
+ description: "Aggressively compress a prompt to save tokens. Strips filler, hedging, connector adverbs, and at the aggressive level rewrites question-style openers and drops articles. Use when the goal is fewer tokens (rate limits, cost), not clarity. For polite tightening with structural feedback, use optimize_prompt instead. Realistic savings are 10 to 25 percent depending on input and level; viral claims of 60 percent or more measure narrow output slices, not full sessions.",
64
+ inputSchema: {
65
+ type: "object",
66
+ properties: {
67
+ text: {
68
+ type: "string",
69
+ description: "The prompt text to compress.",
70
+ },
71
+ level: {
72
+ type: "string",
73
+ enum: ["light", "medium", "aggressive"],
74
+ description: "How aggressive to be. Light: only obvious filler. Medium: also connector adverbs and meta-commentary. Aggressive: also drops articles after task verbs and restates question patterns. Defaults to medium.",
75
+ },
76
+ },
77
+ required: ["text"],
78
+ },
79
+ },
80
+ {
81
+ name: "estimate_cost",
82
+ description: "Estimate the token count and dollar cost of a prompt for a specific model before sending it. Useful for previewing the cost of large prompts, bulk operations, or deciding which model to use.",
83
+ inputSchema: {
84
+ type: "object",
85
+ properties: {
86
+ text: {
87
+ type: "string",
88
+ description: "The prompt text to measure.",
89
+ },
90
+ model: {
91
+ type: "string",
92
+ enum: SUPPORTED_MODELS,
93
+ description: "The target model for the estimate.",
94
+ },
95
+ expectedOutputTokens: {
96
+ type: "number",
97
+ description: "Optional override for expected output token count. When omitted, defaults to min(inputTokens, 1024).",
98
+ },
99
+ },
100
+ required: ["text", "model"],
101
+ },
102
+ },
103
+ ],
104
+ }));
105
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
106
+ if (request.params.name === "ping") {
107
+ return {
108
+ content: [
109
+ {
110
+ type: "text",
111
+ text: `pong from PromptGuard v${PROMPTGUARD_VERSION}`,
112
+ },
113
+ ],
114
+ };
115
+ }
116
+ if (request.params.name === "scan_prompt") {
117
+ const args = (request.params.arguments ?? {});
118
+ if (typeof args.text !== "string") {
119
+ throw new Error("scan_prompt requires a 'text' string argument.");
120
+ }
121
+ const result = scanText(args.text);
122
+ const mode = args.mode ?? "warn";
123
+ const summary = result.findings.length === 0
124
+ ? "No secrets or sensitive data detected."
125
+ : `Found ${result.findings.length} potential issue${result.findings.length === 1 ? "" : "s"}:\n\n` +
126
+ result.findings
127
+ .map((f, i) => `${i + 1}. [${f.severity.toUpperCase()}] ${f.rule}\n` +
128
+ ` Position ${f.start}-${f.end} (length ${f.end - f.start})\n` +
129
+ ` Why: ${f.explanation}`)
130
+ .join("\n\n");
131
+ const payload = {
132
+ findings: result.findings,
133
+ redactedText: mode === "redact" ? result.redactedText : args.text,
134
+ scanMs: Math.round(result.scanMs * 100) / 100,
135
+ rulesRun: result.rulesRun,
136
+ };
137
+ return {
138
+ content: [
139
+ { type: "text", text: summary },
140
+ {
141
+ type: "text",
142
+ text: "```json\n" + JSON.stringify(payload, null, 2) + "\n```",
143
+ },
144
+ ],
145
+ };
146
+ }
147
+ if (request.params.name === "optimize_prompt") {
148
+ const args = (request.params.arguments ?? {});
149
+ if (typeof args.text !== "string") {
150
+ throw new Error("optimize_prompt requires a 'text' string argument.");
151
+ }
152
+ const result = optimizePrompt(args.text);
153
+ let summary;
154
+ if (!result.shouldSuggest) {
155
+ summary = "Prompt looks good. No changes recommended.";
156
+ }
157
+ else {
158
+ const removed = result.optimizations
159
+ .filter((o) => o.after.length === 0)
160
+ .map((o) => `"${o.before.trim()}"`);
161
+ const rewritten = result.optimizations
162
+ .filter((o) => o.after.length > 0)
163
+ .map((o) => `"${o.before.trim()}" to "${o.after.trim()}"`);
164
+ const TIP_LABELS = {
165
+ missing_task_verb: "start with a direct verb (such as Write, Explain, Generate)",
166
+ missing_output_format: "specify the output format (such as bulleted list, JSON, or markdown)",
167
+ };
168
+ const tipParts = result.structuralIssues.map((i) => TIP_LABELS[i.type] ?? i.description);
169
+ summary =
170
+ `Suggested rewrite (saved ${result.tokensSaved} tokens, ${result.percentSaved}% leaner):\n\n` +
171
+ `> ${result.optimizedText}`;
172
+ if (removed.length > 0) {
173
+ summary += `\n\nRemoved: ${removed.join(", ")}.`;
174
+ }
175
+ if (rewritten.length > 0) {
176
+ summary += `\nTightened: ${rewritten.join("; ")}.`;
177
+ }
178
+ if (tipParts.length > 0) {
179
+ summary += `\n\nTip: ${tipParts.join("; ")}.`;
180
+ }
181
+ }
182
+ return {
183
+ content: [
184
+ { type: "text", text: summary },
185
+ {
186
+ type: "text",
187
+ text: "```json\n" + JSON.stringify(result, null, 2) + "\n```",
188
+ },
189
+ ],
190
+ };
191
+ }
192
+ if (request.params.name === "compress_prompt") {
193
+ const args = (request.params.arguments ?? {});
194
+ if (typeof args.text !== "string") {
195
+ throw new Error("compress_prompt requires a 'text' string argument.");
196
+ }
197
+ const level = args.level ?? "medium";
198
+ if (!["light", "medium", "aggressive"].includes(level)) {
199
+ throw new Error("compress_prompt 'level' must be 'light', 'medium', or 'aggressive'.");
200
+ }
201
+ const result = compressPrompt(args.text, level);
202
+ const summary = `Compressed (${result.level}): ${result.originalTokens} to ${result.compressedTokens} tokens, saved ${result.tokensSaved} (${result.percentSaved}% leaner).\n\n` +
203
+ `> ${result.compressedText}\n\n` +
204
+ `Note: ${result.warning}`;
205
+ return {
206
+ content: [
207
+ { type: "text", text: summary },
208
+ {
209
+ type: "text",
210
+ text: "```json\n" + JSON.stringify(result, null, 2) + "\n```",
211
+ },
212
+ ],
213
+ };
214
+ }
215
+ if (request.params.name === "estimate_cost") {
216
+ const args = (request.params.arguments ?? {});
217
+ if (typeof args.text !== "string") {
218
+ throw new Error("estimate_cost requires a 'text' string argument.");
219
+ }
220
+ if (!args.model || !SUPPORTED_MODELS.includes(args.model)) {
221
+ throw new Error(`estimate_cost requires 'model' to be one of: ${SUPPORTED_MODELS.join(", ")}.`);
222
+ }
223
+ const result = estimateCost(args.text, args.model, args.expectedOutputTokens);
224
+ const approxNote = result.approximate
225
+ ? " (token count is an approximation for Claude models, exact for OpenAI)"
226
+ : "";
227
+ const summary = `Model: ${result.model}\n` +
228
+ `Input tokens: ${result.inputTokens}${approxNote}\n` +
229
+ `Estimated output tokens: ${result.estimatedOutputTokens}\n` +
230
+ `Input cost: $${result.inputCostUsd.toFixed(6)}\n` +
231
+ `Estimated output cost: $${result.estimatedOutputCostUsd.toFixed(6)}\n` +
232
+ `Total estimated cost: $${result.totalEstimatedUsd.toFixed(6)}\n` +
233
+ `Pricing last updated: ${result.pricingLastUpdated}`;
234
+ return {
235
+ content: [
236
+ { type: "text", text: summary },
237
+ {
238
+ type: "text",
239
+ text: "```json\n" + JSON.stringify(result, null, 2) + "\n```",
240
+ },
241
+ ],
242
+ };
243
+ }
244
+ throw new Error(`Unknown tool: ${request.params.name}`);
245
+ });
246
+ async function main() {
247
+ const transport = new StdioServerTransport();
248
+ await server.connect(transport);
249
+ // stdout is reserved for MCP protocol; log to stderr.
250
+ console.error(`PromptGuard MCP server v${PROMPTGUARD_VERSION} running on stdio`);
251
+ }
252
+ main().catch((error) => {
253
+ console.error("PromptGuard failed to start:", error);
254
+ process.exit(1);
255
+ });
256
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,235 @@
1
+ import { countTokens } from "./cost.js";
2
+ const SUBSTITUTIONS = [
3
+ // Filler removal: politeness and verbose request openers
4
+ {
5
+ pattern: /\b(could|can|would|will) you (please |kindly )?/gi,
6
+ replacement: "",
7
+ category: "filler_removal",
8
+ description: "removed soft request opener",
9
+ },
10
+ {
11
+ pattern: /\bplease\b ?/gi,
12
+ replacement: "",
13
+ category: "filler_removal",
14
+ description: "removed 'please'",
15
+ },
16
+ {
17
+ pattern: /\bI (would like|want|need) (you )?to /gi,
18
+ replacement: "",
19
+ category: "filler_removal",
20
+ description: "removed verbose request opener",
21
+ },
22
+ {
23
+ pattern: /\bif (it'?s )?(possible|you can|you'?d like|you don'?t mind),?\s*/gi,
24
+ replacement: "",
25
+ category: "hedging",
26
+ description: "removed hedge",
27
+ },
28
+ {
29
+ pattern: /\bthank(s| you)( so much)?( in advance)?[!.]?\s*$/gi,
30
+ replacement: "",
31
+ category: "filler_removal",
32
+ description: "removed trailing thanks",
33
+ },
34
+ {
35
+ pattern: /\bI('?d| would)( really| truly| greatly)? appreciate (it|that|your help)( with (this|that))?[,.]?\s*/gi,
36
+ replacement: "",
37
+ category: "filler_removal",
38
+ description: "removed appreciation filler",
39
+ },
40
+ {
41
+ pattern: /\b(when you (get a chance|have (a )?(moment|time|second))|if you have a moment),?\s*/gi,
42
+ replacement: "",
43
+ category: "filler_removal",
44
+ description: "removed availability hedge",
45
+ },
46
+ // Verbose phrases tightened
47
+ {
48
+ pattern: /\bin order to\b/gi,
49
+ replacement: "to",
50
+ category: "verbose_phrase",
51
+ description: "tightened 'in order to' to 'to'",
52
+ },
53
+ {
54
+ pattern: /\bdue to the fact that\b/gi,
55
+ replacement: "because",
56
+ category: "verbose_phrase",
57
+ description: "tightened 'due to the fact that' to 'because'",
58
+ },
59
+ {
60
+ pattern: /\bat this point in time\b/gi,
61
+ replacement: "now",
62
+ category: "verbose_phrase",
63
+ description: "tightened 'at this point in time' to 'now'",
64
+ },
65
+ {
66
+ pattern: /\bfor the purpose of\b/gi,
67
+ replacement: "to",
68
+ category: "verbose_phrase",
69
+ description: "tightened 'for the purpose of' to 'to'",
70
+ },
71
+ {
72
+ pattern: /\bin the event that\b/gi,
73
+ replacement: "if",
74
+ category: "verbose_phrase",
75
+ description: "tightened 'in the event that' to 'if'",
76
+ },
77
+ {
78
+ pattern: /\bwith regards? to\b/gi,
79
+ replacement: "about",
80
+ category: "verbose_phrase",
81
+ description: "tightened 'with regard(s) to' to 'about'",
82
+ },
83
+ {
84
+ pattern: /\ba (large|huge|massive|significant) number of\b/gi,
85
+ replacement: "many",
86
+ category: "verbose_phrase",
87
+ description: "tightened to 'many'",
88
+ },
89
+ // Hedging
90
+ {
91
+ pattern: /\bI'?m not sure if this is (right|correct),?\s*but,?\s*/gi,
92
+ replacement: "",
93
+ category: "hedging",
94
+ description: "removed uncertainty hedge",
95
+ },
96
+ {
97
+ pattern: /\bthis (might|may) be a (silly|dumb|basic|stupid) question,?\s*but,?\s*/gi,
98
+ replacement: "",
99
+ category: "hedging",
100
+ description: "removed self-deprecating hedge",
101
+ },
102
+ ];
103
+ const TASK_VERBS = new Set([
104
+ "write",
105
+ "create",
106
+ "generate",
107
+ "explain",
108
+ "describe",
109
+ "analyze",
110
+ "compare",
111
+ "summarize",
112
+ "translate",
113
+ "list",
114
+ "show",
115
+ "build",
116
+ "design",
117
+ "fix",
118
+ "debug",
119
+ "review",
120
+ "find",
121
+ "count",
122
+ "extract",
123
+ "convert",
124
+ "refactor",
125
+ "rewrite",
126
+ "draft",
127
+ "improve",
128
+ "optimize",
129
+ "evaluate",
130
+ "rank",
131
+ "classify",
132
+ "calculate",
133
+ "compute",
134
+ "implement",
135
+ "deploy",
136
+ ]);
137
+ function findStructuralIssues(text) {
138
+ const issues = [];
139
+ const trimmed = text.trim();
140
+ if (trimmed.length === 0)
141
+ return issues;
142
+ const firstWord = trimmed.match(/^\w+/)?.[0]?.toLowerCase() ?? "";
143
+ if (firstWord && !TASK_VERBS.has(firstWord)) {
144
+ if (/^(can|could|would|will|is|do|are|i)\b/i.test(trimmed) &&
145
+ trimmed.length > 30) {
146
+ issues.push({
147
+ type: "missing_task_verb",
148
+ description: "Prompt does not start with a direct task verb.",
149
+ suggestion: "Consider starting with an imperative such as Write, Explain, Generate, or Analyze so the model knows exactly what action to take.",
150
+ });
151
+ }
152
+ }
153
+ if (trimmed.length > 120 &&
154
+ !/(format|json|list|bullet|table|paragraph|markdown|csv|yaml|xml)/i.test(trimmed)) {
155
+ issues.push({
156
+ type: "missing_output_format",
157
+ description: "No output format is specified.",
158
+ suggestion: "Specify the desired output shape, for example 'respond as a bulleted list', 'in JSON', or 'in markdown', to reduce iteration.",
159
+ });
160
+ }
161
+ return issues;
162
+ }
163
+ function cleanupSpacing(text, original) {
164
+ let result = text;
165
+ result = result.replace(/ {2,}/g, " ");
166
+ result = result.replace(/\s+([.,!?;:])/g, "$1");
167
+ result = result.replace(/[ \t]+\n/g, "\n");
168
+ result = result.replace(/\n{3,}/g, "\n\n");
169
+ result = result.trim();
170
+ const origFirst = original.trim()[0];
171
+ const resultFirst = result[0];
172
+ if (origFirst &&
173
+ resultFirst &&
174
+ /[A-Z]/.test(origFirst) &&
175
+ /[a-z]/.test(resultFirst)) {
176
+ result = result[0].toUpperCase() + result.slice(1);
177
+ }
178
+ return result;
179
+ }
180
+ export function optimizePrompt(text) {
181
+ const originalTokens = countTokens(text);
182
+ if (originalTokens < 10) {
183
+ return {
184
+ shouldSuggest: false,
185
+ originalText: text,
186
+ optimizedText: text,
187
+ optimizations: [],
188
+ structuralIssues: [],
189
+ originalTokens,
190
+ optimizedTokens: originalTokens,
191
+ tokensSaved: 0,
192
+ percentSaved: 0,
193
+ reason: "Prompt is too short to meaningfully optimize.",
194
+ };
195
+ }
196
+ const optimizations = [];
197
+ let optimized = text;
198
+ for (const sub of SUBSTITUTIONS) {
199
+ optimized = optimized.replace(sub.pattern, (matched) => {
200
+ optimizations.push({
201
+ type: sub.category,
202
+ description: sub.description,
203
+ before: matched,
204
+ after: sub.replacement,
205
+ });
206
+ return sub.replacement;
207
+ });
208
+ }
209
+ optimized = cleanupSpacing(optimized, text);
210
+ const structuralIssues = findStructuralIssues(text);
211
+ const optimizedTokens = countTokens(optimized);
212
+ const tokensSaved = originalTokens - optimizedTokens;
213
+ const percentSaved = originalTokens === 0
214
+ ? 0
215
+ : Math.round((tokensSaved / originalTokens) * 10000) / 100;
216
+ const meaningfulCompression = tokensSaved >= 5 && percentSaved >= 10;
217
+ const shouldSuggest = meaningfulCompression ||
218
+ structuralIssues.length > 0 ||
219
+ optimizations.length >= 3;
220
+ return {
221
+ shouldSuggest,
222
+ originalText: text,
223
+ optimizedText: optimized,
224
+ optimizations,
225
+ structuralIssues,
226
+ originalTokens,
227
+ optimizedTokens,
228
+ tokensSaved,
229
+ percentSaved,
230
+ reason: shouldSuggest
231
+ ? undefined
232
+ : "Prompt is already concise and well-structured; no meaningful optimization available.",
233
+ };
234
+ }
235
+ //# sourceMappingURL=optimize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"optimize.js","sourceRoot":"","sources":["../src/optimize.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@promptguardapp/mcp",
3
+ "version": "0.0.1",
4
+ "description": "Local-first MCP server that scans developer prompts for secrets, PII, and cost before they hit the LLM.",
5
+ "type": "module",
6
+ "bin": {
7
+ "promptguard-mcp": "dist/index.js"
8
+ },
9
+ "main": "dist/index.js",
10
+ "files": [
11
+ "dist",
12
+ "README.md",
13
+ "LICENSE"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc",
17
+ "dev": "tsx src/index.ts",
18
+ "start": "node dist/index.js",
19
+ "test": "vitest run",
20
+ "test:watch": "vitest",
21
+ "typecheck": "tsc --noEmit"
22
+ },
23
+ "keywords": [
24
+ "mcp",
25
+ "claude",
26
+ "prompt-safety",
27
+ "secret-scanning",
28
+ "developer-tools"
29
+ ],
30
+ "author": "Krish Ojha",
31
+ "license": "MIT",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "git+https://github.com/KrishOjha1810/promptguard-mcp.git"
35
+ },
36
+ "bugs": {
37
+ "url": "https://github.com/KrishOjha1810/promptguard-mcp/issues"
38
+ },
39
+ "homepage": "https://github.com/KrishOjha1810/promptguard-mcp#readme",
40
+ "engines": {
41
+ "node": ">=20"
42
+ },
43
+ "dependencies": {
44
+ "@modelcontextprotocol/sdk": "^1.0.0",
45
+ "js-tiktoken": "^1.0.21"
46
+ },
47
+ "devDependencies": {
48
+ "@types/node": "^22.0.0",
49
+ "tsx": "^4.19.0",
50
+ "typescript": "^5.6.0",
51
+ "vitest": "^2.1.0"
52
+ }
53
+ }