@cliwant/mcp-sam-gov 1.13.0 → 1.13.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cliwant/mcp-sam-gov",
3
- "version": "1.13.0",
3
+ "version": "1.13.2",
4
4
  "mcpName": "io.github.cliwant/mcp-sam-gov",
5
5
  "description": "Most comprehensive keyless-first MCP server for US federal + state/local (SLED) contracting + spending + regulation: SAM.gov, USAspending, Federal Register, eCFR, Grants.gov, plus SLED procurement bids (OpenGov, Bonfire, ArcGIS, Socrata 53 hosts). 152 tools (147 need no API key), plug into Claude Desktop / Claude Code / Codex CLI / Cursor / Continue / Gemini CLI.",
6
6
  "keywords": [
package/src/feedback.ts CHANGED
@@ -20,6 +20,13 @@
20
20
  * • Non-nagging. Error links are attached only to the two "something may be
21
21
  * broken" kinds (schema_drift, upstream_unavailable) — never to expected
22
22
  * outcomes (not_found, invalid_input, rate_limited).
23
+ * • Countable. Every prefilled body starts with one fixed HTML comment,
24
+ * `<!-- mcp-sam-gov:tool-report v=<server version> kind=<report kind> -->`
25
+ * (invisible once the issue renders). GitHub drops a prefilled `labels=`
26
+ * for filers without triage rights, so the repo's label-tool-reports
27
+ * workflow reads this marker instead and applies `from-tool`. The marker
28
+ * holds only the server version and the report kind — never a tool
29
+ * argument, query, key, path, or the caller's summary.
23
30
  */
24
31
 
25
32
  export const REPO_URL = "https://github.com/cliwant/mcp-sam-gov";
@@ -30,6 +37,27 @@ export type FeedbackKind = "bug" | "feature" | "wrong_output";
30
37
  const REDACT_NOTE =
31
38
  "⚠️ This is a PUBLIC issue. Do NOT paste API keys, credentials, personal data, or sensitive query values — redact anything private before you submit.";
32
39
 
40
+ /** The fixed token the label-tool-reports workflow looks for in an issue body. */
41
+ export const TOOL_REPORT_MARKER_TOKEN = "mcp-sam-gov:tool-report";
42
+
43
+ // Both marker values come from closed sets (SERVER_VERSION, an error kind or a
44
+ // FeedbackKind), but they are still checked here so the marker can never carry
45
+ // anything else, and can never close the HTML comment early.
46
+ const MARKER_KIND_RE = /^[a-z][a-z_]{0,39}$/;
47
+ const MARKER_VERSION_RE = /^\d{1,4}\.\d{1,4}\.\d{1,4}(?:-[0-9A-Za-z.]{1,20})?$/;
48
+
49
+ /**
50
+ * The one-line, PII-free HTML comment put at the top of every prefilled body:
51
+ * `<!-- mcp-sam-gov:tool-report v=<version> kind=<kind> -->`. A value that does
52
+ * not match its pattern is written as `unknown`. It goes FIRST in the body so a
53
+ * URL cut short at the end still keeps it, and it adds under 100 URL characters.
54
+ */
55
+ export function toolReportMarker(kind: string, version: string): string {
56
+ const v = MARKER_VERSION_RE.test(version) ? version : "unknown";
57
+ const k = MARKER_KIND_RE.test(kind) ? kind : "unknown";
58
+ return `<!-- ${TOOL_REPORT_MARKER_TOKEN} v=${v} kind=${k} -->`;
59
+ }
60
+
33
61
  /**
34
62
  * Build a GitHub "new issue" URL with a prefilled title/body/labels. Everything
35
63
  * is URL-encoded via URLSearchParams. A prefilled label that does not exist in
@@ -54,6 +82,7 @@ export function reportUrlForError(tool: string, kind: string, version: string):
54
82
  ? "schema_drift means the government API very likely changed its response shape, so the wrapper needs updating — this is the single most useful thing to report."
55
83
  : "upstream_unavailable is often a transient government-side outage; please report only if it PERSISTS or the endpoint appears to have permanently moved.";
56
84
  const body = [
85
+ toolReportMarker(kind, version),
57
86
  "**Reporting a tool problem** (this link was suggested by the server).",
58
87
  "",
59
88
  `- **Tool:** \`${tool}\``,
@@ -120,12 +149,16 @@ export type FeedbackResult = {
120
149
  * report into a PREFILLED GitHub new-issue URL for the HUMAN to open and submit.
121
150
  * Pure + keyless: no network, no posting. `summary` is caller-supplied free text
122
151
  * and is trusted to be non-sensitive (the description + privacy note say so).
152
+ * `version` is the server version, used only in the tool-report marker.
123
153
  */
124
- export function feedbackTool(input: {
125
- kind?: FeedbackKind;
126
- tool?: string;
127
- summary?: string;
128
- }): FeedbackResult {
154
+ export function feedbackTool(
155
+ input: {
156
+ kind?: FeedbackKind;
157
+ tool?: string;
158
+ summary?: string;
159
+ },
160
+ version: string,
161
+ ): FeedbackResult {
129
162
  const kind: FeedbackKind = input.kind ?? "bug";
130
163
  const toolPart = input.tool ? `[${input.tool}] ` : "";
131
164
  const summary = (input.summary ?? "").trim();
@@ -135,19 +168,20 @@ export function feedbackTool(input: {
135
168
  ? "**What I want to be able to do:**"
136
169
  : "**What I did, expected, and got:**";
137
170
  const body = [
138
- `**Type:** ${KIND_TITLE[kind]}`,
139
- input.tool ? `**Tool:** \`${input.tool}\`` : "",
140
- "",
141
- `${lead} ${summary || "_(describe)_"}`,
142
- "",
143
- kind === "feature"
144
- ? "**Why it matters / use case:** _(describe)_"
145
- : "**Steps to reproduce:** _(describe — no sensitive values)_",
146
- "",
147
- REDACT_NOTE,
148
- ]
149
- .filter((line, i) => !(line === "" && i === 2 && !input.tool))
150
- .join("\n");
171
+ toolReportMarker(kind, version),
172
+ ...[
173
+ `**Type:** ${KIND_TITLE[kind]}`,
174
+ input.tool ? `**Tool:** \`${input.tool}\`` : "",
175
+ "",
176
+ `${lead} ${summary || "_(describe)_"}`,
177
+ "",
178
+ kind === "feature"
179
+ ? "**Why it matters / use case:** _(describe)_"
180
+ : "**Steps to reproduce:** _(describe — no sensitive values)_",
181
+ "",
182
+ REDACT_NOTE,
183
+ ].filter((line, i) => !(line === "" && i === 2 && !input.tool)),
184
+ ].join("\n");
151
185
  return {
152
186
  reportUrl: buildIssueUrl({ title, body, labels: KIND_LABELS[kind] }),
153
187
  repo: REPO_URL,
@@ -155,6 +189,6 @@ export function feedbackTool(input: {
155
189
  instructions:
156
190
  "Open reportUrl in a browser and submit the issue yourself — the server does NOT post anything automatically. Edit the prefilled title/body first if you like.",
157
191
  privacy:
158
- "The link prefills only your summary + tool name — no API keys, query values, or personal data. Keep it that way; the issue is public.",
192
+ "The link prefills only your summary, tool name, server version and report kind — no API keys, query values, or personal data. Keep it that way; the issue is public.",
159
193
  };
160
194
  }
package/src/server.ts CHANGED
@@ -108,7 +108,7 @@ import { realpathSync } from "node:fs";
108
108
  const SERVER_NAME = "mcp-sam-gov";
109
109
  // Kept in lockstep with package.json / manifest.json / server.json.
110
110
  // Keep in sync with package.json "version" (asserted at release; see CHANGELOG).
111
- const SERVER_VERSION = "1.13.0";
111
+ const SERVER_VERSION = "1.13.2";
112
112
 
113
113
  // ─── Tool input schemas (Zod) ────────────────────────────────────
114
114
 
@@ -6640,7 +6640,7 @@ export const TOOLS: ToolDef[] = [
6640
6640
  description:
6641
6641
  "Report a problem, request a feature, or flag a wrong-looking result for THIS server — returns a PREFILLED GitHub issue link (public repo cliwant/mcp-sam-gov) for the USER to open and submit. KEYLESS. The server does NOT post anything: it only builds the link; the human submits it (nothing is sent automatically, no network call). Use when the user reports a bug, says a tool's output looks wrong, or wants a capability this server doesn't have. Input (all optional): `kind` (bug|feature|wrong_output, default bug), `tool` (the tool it's about), `summary` (a short, NON-SENSITIVE title line). Returns { reportUrl, repo, willPost:false, instructions, privacy }. PRIVACY: never put secrets, personal data, or sensitive query values in `summary` — the issue is PUBLIC and the link prefills only your summary + tool + server version.",
6642
6642
  inputSchema: FeedbackInput,
6643
- handler: async (input) => feedback.feedbackTool(input),
6643
+ handler: async (input) => feedback.feedbackTool(input, SERVER_VERSION),
6644
6644
  }),
6645
6645
  ];
6646
6646