@lexbuild/mcp 1.22.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 ADDED
@@ -0,0 +1,7 @@
1
+ # @lexbuild/mcp
2
+
3
+ ## 1.22.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Add @lexbuild/mcp package — Model Context Protocol server for LexBuild
package/README.md ADDED
@@ -0,0 +1,101 @@
1
+ # @lexbuild/mcp
2
+
3
+ Model Context Protocol server for [LexBuild](https://lexbuild.dev). Gives AI agents direct access to U.S. legal sources: the U.S. Code, Code of Federal Regulations, and Federal Register.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npx @lexbuild/mcp
9
+ ```
10
+
11
+ Or install globally:
12
+
13
+ ```bash
14
+ npm install -g @lexbuild/mcp
15
+ ```
16
+
17
+ ## Configuration
18
+
19
+ ### Claude Desktop
20
+
21
+ Add to your Claude Desktop MCP config (`~/Library/Application Support/Claude/claude_desktop_config.json`):
22
+
23
+ ```json
24
+ {
25
+ "mcpServers": {
26
+ "lexbuild": {
27
+ "command": "npx",
28
+ "args": ["-y", "@lexbuild/mcp"]
29
+ }
30
+ }
31
+ }
32
+ ```
33
+
34
+ ### Claude Code
35
+
36
+ ```json
37
+ {
38
+ "mcpServers": {
39
+ "lexbuild": {
40
+ "command": "npx",
41
+ "args": ["-y", "@lexbuild/mcp"]
42
+ }
43
+ }
44
+ }
45
+ ```
46
+
47
+ ### With an API key (optional, for higher rate limits)
48
+
49
+ ```json
50
+ {
51
+ "mcpServers": {
52
+ "lexbuild": {
53
+ "command": "npx",
54
+ "args": ["-y", "@lexbuild/mcp"],
55
+ "env": {
56
+ "LEXBUILD_API_KEY": "lxb_your_key_here"
57
+ }
58
+ }
59
+ }
60
+ }
61
+ ```
62
+
63
+ ## Tools
64
+
65
+ | Tool | Description |
66
+ |------|-------------|
67
+ | `search_laws` | Full-text search across USC, CFR, and Federal Register |
68
+ | `get_section` | Fetch a single legal section by identifier |
69
+ | `list_titles` | List available titles (USC/CFR) or years (FR) |
70
+ | `get_title` | Get title detail with chapters, or year detail with months |
71
+ | `get_federal_register_document` | Fetch an FR document by document number |
72
+
73
+ ## Resources
74
+
75
+ URI-addressable legal sections via the `lexbuild://` scheme:
76
+
77
+ - `lexbuild://us/usc/t{title}/s{section}` — U.S. Code section
78
+ - `lexbuild://us/cfr/t{title}/s{section}` — CFR section
79
+ - `lexbuild://us/fr/{document_number}` — Federal Register document
80
+
81
+ ## Prompts
82
+
83
+ | Prompt | Description |
84
+ |--------|-------------|
85
+ | `cite_statute` | Generate a Bluebook citation for a USC or CFR section |
86
+ | `summarize_section` | Plain-language summary with audience targeting |
87
+
88
+ ## Hosted Endpoint
89
+
90
+ A hosted MCP server is available at `mcp.lexbuild.dev` using the Streamable HTTP transport. No API key required for basic usage.
91
+
92
+ ## Security
93
+
94
+ - All legal text is wrapped with injection defense markers
95
+ - Response sizes are capped at 256KB to protect model context
96
+ - SSRF protection via egress host allowlist
97
+ - Rate limiting per session (anonymous: 60 req/min)
98
+
99
+ ## License
100
+
101
+ MIT
@@ -0,0 +1,190 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ LexBuildApiClient,
4
+ VERSION,
5
+ createLogger,
6
+ createServer,
7
+ loadConfig
8
+ } from "../chunk-B556FRBS.js";
9
+
10
+ // src/transport/http.ts
11
+ import { Hono } from "hono";
12
+ import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
13
+
14
+ // src/security/rate-limit.ts
15
+ var RateLimiter = class {
16
+ windowMs;
17
+ maxRequests;
18
+ windows = /* @__PURE__ */ new Map();
19
+ constructor(maxRequestsPerMinute) {
20
+ this.windowMs = 6e4;
21
+ this.maxRequests = maxRequestsPerMinute;
22
+ setInterval(() => this.cleanup(), 3e5).unref();
23
+ }
24
+ /** Checks and records a request for the given key. */
25
+ check(key) {
26
+ const now = Date.now();
27
+ const windowStart = now - this.windowMs;
28
+ let timestamps = this.windows.get(key);
29
+ if (!timestamps) {
30
+ timestamps = [];
31
+ this.windows.set(key, timestamps);
32
+ }
33
+ let first = timestamps[0];
34
+ while (first !== void 0 && first < windowStart) {
35
+ timestamps.shift();
36
+ first = timestamps[0];
37
+ }
38
+ if (timestamps.length >= this.maxRequests) {
39
+ const oldestInWindow = timestamps[0] ?? now;
40
+ const retryAfterMs = oldestInWindow + this.windowMs - now;
41
+ return {
42
+ allowed: false,
43
+ remaining: 0,
44
+ retryAfterSeconds: Math.ceil(retryAfterMs / 1e3)
45
+ };
46
+ }
47
+ timestamps.push(now);
48
+ return {
49
+ allowed: true,
50
+ remaining: this.maxRequests - timestamps.length
51
+ };
52
+ }
53
+ /** Removes entries older than 1 hour. */
54
+ cleanup() {
55
+ const cutoff = Date.now() - 36e5;
56
+ for (const [key, timestamps] of this.windows.entries()) {
57
+ const lastTimestamp = timestamps[timestamps.length - 1];
58
+ if (timestamps.length === 0 || lastTimestamp !== void 0 && lastTimestamp < cutoff) {
59
+ this.windows.delete(key);
60
+ }
61
+ }
62
+ }
63
+ };
64
+
65
+ // src/transport/http.ts
66
+ function createHttpApp(deps) {
67
+ const app = new Hono();
68
+ const rateLimiter = new RateLimiter(deps.config.LEXBUILD_MCP_RATE_LIMIT_PER_MIN);
69
+ const logger = deps.logger.child({ transport: "http" });
70
+ const sessions = /* @__PURE__ */ new Map();
71
+ const MAX_SESSIONS = 1e3;
72
+ const SESSION_TTL_MS = 30 * 60 * 1e3;
73
+ const cleanupInterval = setInterval(() => {
74
+ const now = Date.now();
75
+ for (const [id, session] of sessions.entries()) {
76
+ if (now - session.lastActive > SESSION_TTL_MS) {
77
+ sessions.delete(id);
78
+ logger.info("Stale MCP session cleaned up", { sessionId: id });
79
+ }
80
+ }
81
+ }, 6e4);
82
+ cleanupInterval.unref();
83
+ app.get("/healthz", (c) => c.json({ status: "ok" }));
84
+ app.get("/readyz", async (c) => {
85
+ try {
86
+ await deps.api.healthCheck();
87
+ return c.json({ status: "ready" });
88
+ } catch (err) {
89
+ logger.warn("Readiness check failed", {
90
+ error: err instanceof Error ? err.message : String(err)
91
+ });
92
+ return c.json({ status: "not_ready" }, 503);
93
+ }
94
+ });
95
+ app.all("/mcp", async (c) => {
96
+ const sessionId = c.req.header("mcp-session-id");
97
+ const rateLimitKey = sessionId ?? c.req.header("cf-connecting-ip") ?? "anonymous";
98
+ const rateResult = rateLimiter.check(rateLimitKey);
99
+ if (!rateResult.allowed) {
100
+ logger.warn("Rate limit exceeded", { key: rateLimitKey });
101
+ return c.json(
102
+ {
103
+ jsonrpc: "2.0",
104
+ error: { code: -32e3, message: "Rate limit exceeded" },
105
+ id: null
106
+ },
107
+ 429,
108
+ {
109
+ "Retry-After": String(rateResult.retryAfterSeconds ?? 60)
110
+ }
111
+ );
112
+ }
113
+ if (!sessionId) {
114
+ const transport = new WebStandardStreamableHTTPServerTransport({
115
+ sessionIdGenerator: () => crypto.randomUUID(),
116
+ onsessioninitialized: (id) => {
117
+ if (sessions.size >= MAX_SESSIONS) {
118
+ logger.warn("Max sessions reached, rejecting new session", {
119
+ maxSessions: MAX_SESSIONS
120
+ });
121
+ return;
122
+ }
123
+ sessions.set(id, { transport, lastActive: Date.now() });
124
+ logger.info("MCP session initialized", { sessionId: id });
125
+ },
126
+ onsessionclosed: (id) => {
127
+ sessions.delete(id);
128
+ logger.info("MCP session closed", { sessionId: id });
129
+ }
130
+ });
131
+ const server = createServer(deps);
132
+ await server.connect(transport);
133
+ return transport.handleRequest(c.req.raw);
134
+ }
135
+ const existingSession = sessions.get(sessionId);
136
+ if (!existingSession) {
137
+ return c.json(
138
+ {
139
+ jsonrpc: "2.0",
140
+ error: { code: -32e3, message: "Session not found" },
141
+ id: null
142
+ },
143
+ 404
144
+ );
145
+ }
146
+ existingSession.lastActive = Date.now();
147
+ return existingSession.transport.handleRequest(c.req.raw);
148
+ });
149
+ app.notFound((c) => c.json({ error: "Not found" }, 404));
150
+ return app;
151
+ }
152
+ async function startHttpServer(deps, logger) {
153
+ const { serve } = await import("@hono/node-server");
154
+ const app = createHttpApp(deps);
155
+ serve(
156
+ {
157
+ fetch: app.fetch,
158
+ hostname: deps.config.LEXBUILD_MCP_HTTP_HOST,
159
+ port: deps.config.LEXBUILD_MCP_HTTP_PORT
160
+ },
161
+ (info) => {
162
+ logger.info("lexbuild-mcp HTTP server ready", {
163
+ host: info.address,
164
+ port: info.port
165
+ });
166
+ }
167
+ );
168
+ }
169
+
170
+ // src/bin/http.ts
171
+ try {
172
+ const config = loadConfig();
173
+ const logger = createLogger(config.LEXBUILD_MCP_LOG_LEVEL, { service: "lexbuild-mcp" });
174
+ const api = new LexBuildApiClient({
175
+ baseUrl: config.LEXBUILD_API_URL,
176
+ apiKey: config.LEXBUILD_API_KEY,
177
+ logger
178
+ });
179
+ await startHttpServer({ config, logger, api, version: VERSION }, logger);
180
+ } catch (err) {
181
+ console.error(
182
+ JSON.stringify({
183
+ level: "error",
184
+ msg: "lexbuild-mcp HTTP server failed to start",
185
+ error: err instanceof Error ? err.message : String(err)
186
+ })
187
+ );
188
+ process.exit(1);
189
+ }
190
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/transport/http.ts","../../src/security/rate-limit.ts","../../src/bin/http.ts"],"sourcesContent":["/**\n * HTTP transport using Hono and MCP Streamable HTTP.\n * Serves the hosted MCP endpoint at mcp.lexbuild.dev.\n */\nimport { Hono } from \"hono\";\nimport { WebStandardStreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js\";\nimport { createServer } from \"../server/create-server.js\";\nimport type { ServerDeps } from \"../server/create-server.js\";\nimport { RateLimiter } from \"../security/rate-limit.js\";\nimport type { Logger } from \"../lib/logger.js\";\n\n/** Creates the HTTP app with MCP transport, health endpoints, and rate limiting. */\nexport function createHttpApp(deps: ServerDeps): Hono {\n const app = new Hono();\n const rateLimiter = new RateLimiter(deps.config.LEXBUILD_MCP_RATE_LIMIT_PER_MIN);\n const logger = deps.logger.child({ transport: \"http\" });\n\n // Track active transports by session ID with last-activity timestamps\n const sessions = new Map<string, { transport: WebStandardStreamableHTTPServerTransport; lastActive: number }>();\n const MAX_SESSIONS = 1000;\n const SESSION_TTL_MS = 30 * 60 * 1000; // 30 minutes\n\n // Periodic cleanup of stale sessions\n const cleanupInterval = setInterval(() => {\n const now = Date.now();\n for (const [id, session] of sessions.entries()) {\n if (now - session.lastActive > SESSION_TTL_MS) {\n sessions.delete(id);\n logger.info(\"Stale MCP session cleaned up\", { sessionId: id });\n }\n }\n }, 60_000);\n cleanupInterval.unref();\n\n // Health check — no auth\n app.get(\"/healthz\", (c) => c.json({ status: \"ok\" }));\n\n // Readiness check — pings the Data API\n app.get(\"/readyz\", async (c) => {\n try {\n await deps.api.healthCheck();\n return c.json({ status: \"ready\" });\n } catch (err) {\n logger.warn(\"Readiness check failed\", {\n error: err instanceof Error ? err.message : String(err),\n });\n return c.json({ status: \"not_ready\" }, 503);\n }\n });\n\n // MCP Streamable HTTP endpoint\n app.all(\"/mcp\", async (c) => {\n // Rate limit by session ID header or IP\n const sessionId = c.req.header(\"mcp-session-id\");\n const rateLimitKey = sessionId ?? c.req.header(\"cf-connecting-ip\") ?? \"anonymous\";\n const rateResult = rateLimiter.check(rateLimitKey);\n\n if (!rateResult.allowed) {\n logger.warn(\"Rate limit exceeded\", { key: rateLimitKey });\n return c.json(\n {\n jsonrpc: \"2.0\",\n error: { code: -32000, message: \"Rate limit exceeded\" },\n id: null,\n },\n 429,\n {\n \"Retry-After\": String(rateResult.retryAfterSeconds ?? 60),\n },\n );\n }\n\n // For initialization requests (no session ID), create a new transport\n if (!sessionId) {\n const transport = new WebStandardStreamableHTTPServerTransport({\n sessionIdGenerator: () => crypto.randomUUID(),\n onsessioninitialized: (id) => {\n if (sessions.size >= MAX_SESSIONS) {\n logger.warn(\"Max sessions reached, rejecting new session\", {\n maxSessions: MAX_SESSIONS,\n });\n return;\n }\n sessions.set(id, { transport, lastActive: Date.now() });\n logger.info(\"MCP session initialized\", { sessionId: id });\n },\n onsessionclosed: (id) => {\n sessions.delete(id);\n logger.info(\"MCP session closed\", { sessionId: id });\n },\n });\n\n const server = createServer(deps);\n await server.connect(transport);\n return transport.handleRequest(c.req.raw);\n }\n\n // For existing sessions, look up the transport\n const existingSession = sessions.get(sessionId);\n if (!existingSession) {\n return c.json(\n {\n jsonrpc: \"2.0\",\n error: { code: -32000, message: \"Session not found\" },\n id: null,\n },\n 404,\n );\n }\n\n existingSession.lastActive = Date.now();\n return existingSession.transport.handleRequest(c.req.raw);\n });\n\n // Log unhandled routes\n app.notFound((c) => c.json({ error: \"Not found\" }, 404));\n\n return app;\n}\n\n/** Starts the HTTP server. Exported for use by the bin entrypoint. */\nexport async function startHttpServer(deps: ServerDeps, logger: Logger): Promise<void> {\n const { serve } = await import(\"@hono/node-server\");\n\n const app = createHttpApp(deps);\n\n serve(\n {\n fetch: app.fetch,\n hostname: deps.config.LEXBUILD_MCP_HTTP_HOST,\n port: deps.config.LEXBUILD_MCP_HTTP_PORT,\n },\n (info) => {\n logger.info(\"lexbuild-mcp HTTP server ready\", {\n host: info.address,\n port: info.port,\n });\n },\n );\n}\n","/**\n * In-memory sliding window rate limiter for the HTTP transport.\n * Keys by session ID or IP. Anonymous sessions use the configured default limit.\n */\n\n/** Rate limit check result. */\nexport interface RateLimitResult {\n allowed: boolean;\n remaining: number;\n retryAfterSeconds?: number | undefined;\n}\n\n/** In-memory sliding window rate limiter. */\nexport class RateLimiter {\n private readonly windowMs: number;\n private readonly maxRequests: number;\n private readonly windows: Map<string, number[]> = new Map();\n\n constructor(maxRequestsPerMinute: number) {\n this.windowMs = 60_000;\n this.maxRequests = maxRequestsPerMinute;\n\n // Periodic cleanup of stale entries\n setInterval(() => this.cleanup(), 300_000).unref();\n }\n\n /** Checks and records a request for the given key. */\n check(key: string): RateLimitResult {\n const now = Date.now();\n const windowStart = now - this.windowMs;\n\n let timestamps = this.windows.get(key);\n if (!timestamps) {\n timestamps = [];\n this.windows.set(key, timestamps);\n }\n\n // Remove expired timestamps\n let first = timestamps[0];\n while (first !== undefined && first < windowStart) {\n timestamps.shift();\n first = timestamps[0];\n }\n\n if (timestamps.length >= this.maxRequests) {\n const oldestInWindow = timestamps[0] ?? now;\n const retryAfterMs = oldestInWindow + this.windowMs - now;\n return {\n allowed: false,\n remaining: 0,\n retryAfterSeconds: Math.ceil(retryAfterMs / 1000),\n };\n }\n\n timestamps.push(now);\n return {\n allowed: true,\n remaining: this.maxRequests - timestamps.length,\n };\n }\n\n /** Removes entries older than 1 hour. */\n private cleanup(): void {\n const cutoff = Date.now() - 3_600_000;\n for (const [key, timestamps] of this.windows.entries()) {\n const lastTimestamp = timestamps[timestamps.length - 1];\n if (timestamps.length === 0 || (lastTimestamp !== undefined && lastTimestamp < cutoff)) {\n this.windows.delete(key);\n }\n }\n }\n}\n","/**\n * HTTP transport entrypoint for the hosted MCP server at mcp.lexbuild.dev.\n * Serves Streamable HTTP transport via Hono.\n */\nimport { loadConfig } from \"../config.js\";\nimport { createLogger } from \"../lib/logger.js\";\nimport { LexBuildApiClient } from \"../api/client.js\";\nimport { startHttpServer } from \"../transport/http.js\";\nimport { VERSION } from \"../lib/version.js\";\n\ntry {\n const config = loadConfig();\n const logger = createLogger(config.LEXBUILD_MCP_LOG_LEVEL, { service: \"lexbuild-mcp\" });\n const api = new LexBuildApiClient({\n baseUrl: config.LEXBUILD_API_URL,\n apiKey: config.LEXBUILD_API_KEY,\n logger,\n });\n\n await startHttpServer({ config, logger, api, version: VERSION }, logger);\n} catch (err) {\n console.error(\n JSON.stringify({\n level: \"error\",\n msg: \"lexbuild-mcp HTTP server failed to start\",\n error: err instanceof Error ? err.message : String(err),\n }),\n );\n process.exit(1);\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ LexBuildApiClient,
4
+ VERSION,
5
+ createLogger,
6
+ createServer,
7
+ loadConfig
8
+ } from "../chunk-B556FRBS.js";
9
+
10
+ // src/bin/stdio.ts
11
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
12
+ try {
13
+ const config = loadConfig();
14
+ const logger = createLogger(config.LEXBUILD_MCP_LOG_LEVEL, { service: "lexbuild-mcp" });
15
+ const api = new LexBuildApiClient({
16
+ baseUrl: config.LEXBUILD_API_URL,
17
+ apiKey: config.LEXBUILD_API_KEY,
18
+ logger
19
+ });
20
+ const server = createServer({ config, logger, api, version: VERSION });
21
+ const transport = new StdioServerTransport();
22
+ await server.connect(transport);
23
+ logger.info("lexbuild-mcp ready", { transport: "stdio", version: VERSION });
24
+ } catch (err) {
25
+ console.error(
26
+ JSON.stringify({
27
+ level: "error",
28
+ msg: "lexbuild-mcp failed to start",
29
+ error: err instanceof Error ? err.message : String(err)
30
+ })
31
+ );
32
+ process.exit(1);
33
+ }
34
+ //# sourceMappingURL=stdio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/bin/stdio.ts"],"sourcesContent":["/**\n * Stdio transport entrypoint for local MCP client integration.\n * Spawned as a subprocess by Claude Desktop, Claude Code, Cursor, etc.\n */\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { createServer } from \"../server/create-server.js\";\nimport { loadConfig } from \"../config.js\";\nimport { createLogger } from \"../lib/logger.js\";\nimport { LexBuildApiClient } from \"../api/client.js\";\nimport { VERSION } from \"../lib/version.js\";\n\ntry {\n const config = loadConfig();\n const logger = createLogger(config.LEXBUILD_MCP_LOG_LEVEL, { service: \"lexbuild-mcp\" });\n const api = new LexBuildApiClient({\n baseUrl: config.LEXBUILD_API_URL,\n apiKey: config.LEXBUILD_API_KEY,\n logger,\n });\n\n const server = createServer({ config, logger, api, version: VERSION });\n const transport = new StdioServerTransport();\n await server.connect(transport);\n logger.info(\"lexbuild-mcp ready\", { transport: \"stdio\", version: VERSION });\n} catch (err) {\n console.error(\n JSON.stringify({\n level: \"error\",\n msg: \"lexbuild-mcp failed to start\",\n error: err instanceof Error ? err.message : String(err),\n }),\n );\n process.exit(1);\n}\n"],"mappings":";;;;;;;;;;AAIA,SAAS,4BAA4B;AAOrC,IAAI;AACF,QAAM,SAAS,WAAW;AAC1B,QAAM,SAAS,aAAa,OAAO,wBAAwB,EAAE,SAAS,eAAe,CAAC;AACtF,QAAM,MAAM,IAAI,kBAAkB;AAAA,IAChC,SAAS,OAAO;AAAA,IAChB,QAAQ,OAAO;AAAA,IACf;AAAA,EACF,CAAC;AAED,QAAM,SAAS,aAAa,EAAE,QAAQ,QAAQ,KAAK,SAAS,QAAQ,CAAC;AACrE,QAAM,YAAY,IAAI,qBAAqB;AAC3C,QAAM,OAAO,QAAQ,SAAS;AAC9B,SAAO,KAAK,sBAAsB,EAAE,WAAW,SAAS,SAAS,QAAQ,CAAC;AAC5E,SAAS,KAAK;AACZ,UAAQ;AAAA,IACN,KAAK,UAAU;AAAA,MACb,OAAO;AAAA,MACP,KAAK;AAAA,MACL,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,IACxD,CAAC;AAAA,EACH;AACA,UAAQ,KAAK,CAAC;AAChB;","names":[]}