@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 +7 -0
- package/README.md +101 -0
- package/dist/bin/http.js +190 -0
- package/dist/bin/http.js.map +1 -0
- package/dist/bin/stdio.js +34 -0
- package/dist/bin/stdio.js.map +1 -0
- package/dist/chunk-B556FRBS.js +701 -0
- package/dist/chunk-B556FRBS.js.map +1 -0
- package/dist/index.d.ts +280 -0
- package/dist/index.js +573 -0
- package/dist/index.js.map +1 -0
- package/package.json +76 -0
package/CHANGELOG.md
ADDED
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
|
package/dist/bin/http.js
ADDED
|
@@ -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":";;;;;;;;;;AAIA,SAAS,YAAY;AACrB,SAAS,gDAAgD;;;ACQlD,IAAM,cAAN,MAAkB;AAAA,EACN;AAAA,EACA;AAAA,EACA,UAAiC,oBAAI,IAAI;AAAA,EAE1D,YAAY,sBAA8B;AACxC,SAAK,WAAW;AAChB,SAAK,cAAc;AAGnB,gBAAY,MAAM,KAAK,QAAQ,GAAG,GAAO,EAAE,MAAM;AAAA,EACnD;AAAA;AAAA,EAGA,MAAM,KAA8B;AAClC,UAAM,MAAM,KAAK,IAAI;AACrB,UAAM,cAAc,MAAM,KAAK;AAE/B,QAAI,aAAa,KAAK,QAAQ,IAAI,GAAG;AACrC,QAAI,CAAC,YAAY;AACf,mBAAa,CAAC;AACd,WAAK,QAAQ,IAAI,KAAK,UAAU;AAAA,IAClC;AAGA,QAAI,QAAQ,WAAW,CAAC;AACxB,WAAO,UAAU,UAAa,QAAQ,aAAa;AACjD,iBAAW,MAAM;AACjB,cAAQ,WAAW,CAAC;AAAA,IACtB;AAEA,QAAI,WAAW,UAAU,KAAK,aAAa;AACzC,YAAM,iBAAiB,WAAW,CAAC,KAAK;AACxC,YAAM,eAAe,iBAAiB,KAAK,WAAW;AACtD,aAAO;AAAA,QACL,SAAS;AAAA,QACT,WAAW;AAAA,QACX,mBAAmB,KAAK,KAAK,eAAe,GAAI;AAAA,MAClD;AAAA,IACF;AAEA,eAAW,KAAK,GAAG;AACnB,WAAO;AAAA,MACL,SAAS;AAAA,MACT,WAAW,KAAK,cAAc,WAAW;AAAA,IAC3C;AAAA,EACF;AAAA;AAAA,EAGQ,UAAgB;AACtB,UAAM,SAAS,KAAK,IAAI,IAAI;AAC5B,eAAW,CAAC,KAAK,UAAU,KAAK,KAAK,QAAQ,QAAQ,GAAG;AACtD,YAAM,gBAAgB,WAAW,WAAW,SAAS,CAAC;AACtD,UAAI,WAAW,WAAW,KAAM,kBAAkB,UAAa,gBAAgB,QAAS;AACtF,aAAK,QAAQ,OAAO,GAAG;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AACF;;;AD3DO,SAAS,cAAc,MAAwB;AACpD,QAAM,MAAM,IAAI,KAAK;AACrB,QAAM,cAAc,IAAI,YAAY,KAAK,OAAO,+BAA+B;AAC/E,QAAM,SAAS,KAAK,OAAO,MAAM,EAAE,WAAW,OAAO,CAAC;AAGtD,QAAM,WAAW,oBAAI,IAAyF;AAC9G,QAAM,eAAe;AACrB,QAAM,iBAAiB,KAAK,KAAK;AAGjC,QAAM,kBAAkB,YAAY,MAAM;AACxC,UAAM,MAAM,KAAK,IAAI;AACrB,eAAW,CAAC,IAAI,OAAO,KAAK,SAAS,QAAQ,GAAG;AAC9C,UAAI,MAAM,QAAQ,aAAa,gBAAgB;AAC7C,iBAAS,OAAO,EAAE;AAClB,eAAO,KAAK,gCAAgC,EAAE,WAAW,GAAG,CAAC;AAAA,MAC/D;AAAA,IACF;AAAA,EACF,GAAG,GAAM;AACT,kBAAgB,MAAM;AAGtB,MAAI,IAAI,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,KAAK,CAAC,CAAC;AAGnD,MAAI,IAAI,WAAW,OAAO,MAAM;AAC9B,QAAI;AACF,YAAM,KAAK,IAAI,YAAY;AAC3B,aAAO,EAAE,KAAK,EAAE,QAAQ,QAAQ,CAAC;AAAA,IACnC,SAAS,KAAK;AACZ,aAAO,KAAK,0BAA0B;AAAA,QACpC,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MACxD,CAAC;AACD,aAAO,EAAE,KAAK,EAAE,QAAQ,YAAY,GAAG,GAAG;AAAA,IAC5C;AAAA,EACF,CAAC;AAGD,MAAI,IAAI,QAAQ,OAAO,MAAM;AAE3B,UAAM,YAAY,EAAE,IAAI,OAAO,gBAAgB;AAC/C,UAAM,eAAe,aAAa,EAAE,IAAI,OAAO,kBAAkB,KAAK;AACtE,UAAM,aAAa,YAAY,MAAM,YAAY;AAEjD,QAAI,CAAC,WAAW,SAAS;AACvB,aAAO,KAAK,uBAAuB,EAAE,KAAK,aAAa,CAAC;AACxD,aAAO,EAAE;AAAA,QACP;AAAA,UACE,SAAS;AAAA,UACT,OAAO,EAAE,MAAM,OAAQ,SAAS,sBAAsB;AAAA,UACtD,IAAI;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,UACE,eAAe,OAAO,WAAW,qBAAqB,EAAE;AAAA,QAC1D;AAAA,MACF;AAAA,IACF;AAGA,QAAI,CAAC,WAAW;AACd,YAAM,YAAY,IAAI,yCAAyC;AAAA,QAC7D,oBAAoB,MAAM,OAAO,WAAW;AAAA,QAC5C,sBAAsB,CAAC,OAAO;AAC5B,cAAI,SAAS,QAAQ,cAAc;AACjC,mBAAO,KAAK,+CAA+C;AAAA,cACzD,aAAa;AAAA,YACf,CAAC;AACD;AAAA,UACF;AACA,mBAAS,IAAI,IAAI,EAAE,WAAW,YAAY,KAAK,IAAI,EAAE,CAAC;AACtD,iBAAO,KAAK,2BAA2B,EAAE,WAAW,GAAG,CAAC;AAAA,QAC1D;AAAA,QACA,iBAAiB,CAAC,OAAO;AACvB,mBAAS,OAAO,EAAE;AAClB,iBAAO,KAAK,sBAAsB,EAAE,WAAW,GAAG,CAAC;AAAA,QACrD;AAAA,MACF,CAAC;AAED,YAAM,SAAS,aAAa,IAAI;AAChC,YAAM,OAAO,QAAQ,SAAS;AAC9B,aAAO,UAAU,cAAc,EAAE,IAAI,GAAG;AAAA,IAC1C;AAGA,UAAM,kBAAkB,SAAS,IAAI,SAAS;AAC9C,QAAI,CAAC,iBAAiB;AACpB,aAAO,EAAE;AAAA,QACP;AAAA,UACE,SAAS;AAAA,UACT,OAAO,EAAE,MAAM,OAAQ,SAAS,oBAAoB;AAAA,UACpD,IAAI;AAAA,QACN;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,oBAAgB,aAAa,KAAK,IAAI;AACtC,WAAO,gBAAgB,UAAU,cAAc,EAAE,IAAI,GAAG;AAAA,EAC1D,CAAC;AAGD,MAAI,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,YAAY,GAAG,GAAG,CAAC;AAEvD,SAAO;AACT;AAGA,eAAsB,gBAAgB,MAAkB,QAA+B;AACrF,QAAM,EAAE,MAAM,IAAI,MAAM,OAAO,mBAAmB;AAElD,QAAM,MAAM,cAAc,IAAI;AAE9B;AAAA,IACE;AAAA,MACE,OAAO,IAAI;AAAA,MACX,UAAU,KAAK,OAAO;AAAA,MACtB,MAAM,KAAK,OAAO;AAAA,IACpB;AAAA,IACA,CAAC,SAAS;AACR,aAAO,KAAK,kCAAkC;AAAA,QAC5C,MAAM,KAAK;AAAA,QACX,MAAM,KAAK;AAAA,MACb,CAAC;AAAA,IACH;AAAA,EACF;AACF;;;AEjIA,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,gBAAgB,EAAE,QAAQ,QAAQ,KAAK,SAAS,QAAQ,GAAG,MAAM;AACzE,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":[]}
|
|
@@ -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":[]}
|