@fhirfly-io/mcp-server 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 FHIRfly.io LLC
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,178 @@
1
+ # @fhirfly-io/mcp-server
2
+
3
+ MCP (Model Context Protocol) server for connecting Claude Desktop to [FHIRfly](https://fhirfly.io) healthcare reference data APIs.
4
+
5
+ ## What is this?
6
+
7
+ This package lets Claude Desktop look up real healthcare reference data including:
8
+
9
+ - **NDC** - Drug products and packages (FDA)
10
+ - **NPI** - Healthcare provider identifiers (CMS)
11
+ - **RxNorm** - Drug terminology (NLM)
12
+ - **LOINC** - Laboratory codes (Regenstrief Institute)
13
+ - **ICD-10** - Diagnosis and procedure codes (CMS)
14
+ - **CVX/MVX** - Vaccine codes (CDC)
15
+ - **FDA Drug Labels** - Prescribing information
16
+
17
+ When you ask Claude about medications, providers, or clinical codes, it can look up accurate, current information instead of relying on training data.
18
+
19
+ ## Prerequisites
20
+
21
+ 1. **Claude Desktop** - Download from [claude.ai/download](https://claude.ai/download)
22
+ 2. **Node.js 18+** - Download from [nodejs.org](https://nodejs.org)
23
+ 3. **FHIRfly API Key** - Get one at [fhirfly.io](https://fhirfly.io) (free tier available)
24
+
25
+ ## Quick Setup
26
+
27
+ ### Step 1: Get a FHIRfly API Key
28
+
29
+ 1. Go to [fhirfly.io](https://fhirfly.io) and sign up
30
+ 2. Navigate to **Dashboard > Credentials**
31
+ 3. Click **Create Credential** and select **MCP (Claude Desktop)**
32
+ 4. Copy your API key (starts with `ffly_`)
33
+
34
+ ### Step 2: Configure Claude Desktop
35
+
36
+ Find your Claude Desktop config file:
37
+
38
+ - **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
39
+ - **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
40
+
41
+ Add the FHIRfly server configuration:
42
+
43
+ ```json
44
+ {
45
+ "mcpServers": {
46
+ "fhirfly": {
47
+ "command": "npx",
48
+ "args": ["-y", "@fhirfly-io/mcp-server"],
49
+ "env": {
50
+ "FHIRFLY_API_KEY": "ffly_live_your_key_here"
51
+ }
52
+ }
53
+ }
54
+ }
55
+ ```
56
+
57
+ Replace `ffly_live_your_key_here` with your actual API key.
58
+
59
+ ### Step 3: Restart Claude Desktop
60
+
61
+ Completely quit Claude Desktop and reopen it. The FHIRfly tools should now be available.
62
+
63
+ ## Verify It Works
64
+
65
+ Try asking Claude:
66
+
67
+ - "What is NDC 0069-0151-01?"
68
+ - "Look up NPI 1234567893"
69
+ - "Search for COVID vaccines in the CVX database"
70
+ - "What are the drug interactions for Lipitor?"
71
+
72
+ Claude should use the FHIRfly tools to look up real data.
73
+
74
+ ## Available Tools
75
+
76
+ | Tool | Description |
77
+ |------|-------------|
78
+ | `ndc_get` | Look up drug by NDC code |
79
+ | `ndc_search` | Search drugs by name, ingredient, etc. |
80
+ | `npi_get` | Look up provider by NPI number |
81
+ | `npi_search` | Search providers by name, specialty, location |
82
+ | `rxnorm_get` | Look up drug by RxCUI |
83
+ | `rxnorm_search` | Search drug terminology |
84
+ | `loinc_get` | Look up lab test by LOINC code |
85
+ | `loinc_search` | Search lab codes |
86
+ | `icd10_get` | Look up diagnosis/procedure code |
87
+ | `icd10_search` | Search ICD-10 codes |
88
+ | `cvx_get` | Look up vaccine by CVX code |
89
+ | `cvx_search` | Search vaccine codes |
90
+ | `mvx_get` | Look up vaccine manufacturer |
91
+ | `mvx_search` | Search manufacturers |
92
+ | `fda_label_lookup` | Look up FDA drug label |
93
+ | `fda_label_search` | Search drug labels |
94
+ | `fda_label_safety` | Get safety info (boxed warnings, contraindications) |
95
+ | `fda_label_interactions` | Get drug interaction info |
96
+ | `fda_label_dosing` | Get dosing information |
97
+ | `fda_label_sections` | Get specific label sections |
98
+
99
+ ## Configuration Options
100
+
101
+ | Environment Variable | Description | Default |
102
+ |---------------------|-------------|---------|
103
+ | `FHIRFLY_API_KEY` | Your FHIRfly API key (required) | - |
104
+ | `FHIRFLY_API_URL` | API base URL | `https://api.fhirfly.io` |
105
+ | `FHIRFLY_DEBUG` | Enable debug logging (`1` or `true`) | `false` |
106
+
107
+ ## Troubleshooting
108
+
109
+ ### "FHIRFLY_API_KEY environment variable is required"
110
+
111
+ Your API key isn't configured. Make sure:
112
+ 1. You have a valid API key from [fhirfly.io](https://fhirfly.io)
113
+ 2. It's set in the `env` section of your Claude Desktop config
114
+ 3. The key starts with `ffly_`
115
+
116
+ ### "Invalid API key format"
117
+
118
+ FHIRfly API keys start with `ffly_`. Check that you copied the full key.
119
+
120
+ ### "Authentication failed"
121
+
122
+ Your API key may be invalid or expired. Generate a new one at [fhirfly.io/dashboard/credentials](https://fhirfly.io/dashboard/credentials).
123
+
124
+ ### Claude doesn't show FHIRfly tools
125
+
126
+ 1. Make sure you completely quit and restarted Claude Desktop
127
+ 2. Check your config file syntax (must be valid JSON)
128
+ 3. Enable debug mode to see what's happening:
129
+
130
+ ```json
131
+ {
132
+ "mcpServers": {
133
+ "fhirfly": {
134
+ "command": "npx",
135
+ "args": ["-y", "@fhirfly-io/mcp-server"],
136
+ "env": {
137
+ "FHIRFLY_API_KEY": "your_key",
138
+ "FHIRFLY_DEBUG": "1"
139
+ }
140
+ }
141
+ }
142
+ }
143
+ ```
144
+
145
+ ### "Rate limit exceeded"
146
+
147
+ You've hit your plan's rate limit. Wait a moment and try again, or upgrade your plan at [fhirfly.io](https://fhirfly.io).
148
+
149
+ ## How It Works
150
+
151
+ ```
152
+ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
153
+ │ Claude Desktop │────▶│ This Package │────▶│ FHIRfly API │
154
+ │ │ │ (runs locally) │ │ (cloud) │
155
+ │ "What is │◀────│ │◀────│ │
156
+ │ NDC 123..." │ │ Translates MCP │ │ Returns drug │
157
+ │ │ │ ↔ HTTPS │ │ data │
158
+ └─────────────────┘ └─────────────────┘ └─────────────────┘
159
+ ```
160
+
161
+ This package runs on your computer as a bridge between Claude Desktop and the FHIRfly API. It:
162
+
163
+ 1. Receives requests from Claude Desktop via stdin
164
+ 2. Translates them to HTTPS requests to FHIRfly
165
+ 3. Returns the results to Claude via stdout
166
+
167
+ Your API key is sent to FHIRfly over HTTPS. No healthcare data is stored locally.
168
+
169
+ ## Links
170
+
171
+ - [FHIRfly Documentation](https://fhirfly.io/docs)
172
+ - [MCP Setup Guide](https://fhirfly.io/docs/mcp/claude-desktop)
173
+ - [Get an API Key](https://fhirfly.io)
174
+ - [Report Issues](https://github.com/FHIRfly-io/fhirfly-mcp-server/issues)
175
+
176
+ ## License
177
+
178
+ MIT - see [LICENSE](./LICENSE)
package/dist/cli.js ADDED
@@ -0,0 +1,431 @@
1
+ #!/usr/bin/env node
2
+ import { createInterface } from 'readline';
3
+
4
+ var StdioTransport = class {
5
+ handler = null;
6
+ debug;
7
+ pendingRequests = 0;
8
+ stdinClosed = false;
9
+ constructor(debug = false) {
10
+ this.debug = debug;
11
+ }
12
+ /**
13
+ * Set the handler for incoming messages
14
+ */
15
+ setHandler(handler) {
16
+ this.handler = handler;
17
+ }
18
+ /**
19
+ * Start listening for messages on stdin
20
+ */
21
+ start() {
22
+ const rl = createInterface({
23
+ input: process.stdin,
24
+ output: process.stdout,
25
+ terminal: false
26
+ });
27
+ let buffer = "";
28
+ rl.on("line", async (line) => {
29
+ buffer += line;
30
+ try {
31
+ const request = JSON.parse(buffer);
32
+ buffer = "";
33
+ if (this.debug) {
34
+ console.error("[MCP DEBUG] Received:", JSON.stringify(request, null, 2));
35
+ }
36
+ if (this.handler) {
37
+ this.pendingRequests++;
38
+ try {
39
+ const response = await this.handler(request);
40
+ this.send(response);
41
+ } finally {
42
+ this.pendingRequests--;
43
+ this.maybeExit();
44
+ }
45
+ }
46
+ } catch {
47
+ if (line.trim().endsWith("}")) {
48
+ this.sendError(null, -32700, "Parse error: Invalid JSON");
49
+ buffer = "";
50
+ }
51
+ }
52
+ });
53
+ rl.on("close", () => {
54
+ this.stdinClosed = true;
55
+ if (this.debug) {
56
+ console.error("[MCP DEBUG] stdin closed, waiting for pending requests...");
57
+ }
58
+ this.maybeExit();
59
+ });
60
+ process.stdin.on("error", (err) => {
61
+ if (this.debug) {
62
+ console.error("[MCP DEBUG] stdin error:", err.message);
63
+ }
64
+ });
65
+ }
66
+ /**
67
+ * Exit if stdin is closed and no pending requests
68
+ */
69
+ maybeExit() {
70
+ if (this.stdinClosed && this.pendingRequests === 0) {
71
+ if (this.debug) {
72
+ console.error("[MCP DEBUG] All requests complete, exiting");
73
+ }
74
+ process.exit(0);
75
+ }
76
+ }
77
+ /**
78
+ * Send a JSON-RPC response to stdout
79
+ */
80
+ send(response) {
81
+ const message = JSON.stringify(response);
82
+ if (this.debug) {
83
+ console.error("[MCP DEBUG] Sending:", JSON.stringify(response, null, 2));
84
+ }
85
+ process.stdout.write(message + "\n");
86
+ }
87
+ /**
88
+ * Send an error response
89
+ */
90
+ sendError(id, code, message, data) {
91
+ this.send({
92
+ jsonrpc: "2.0",
93
+ id,
94
+ error: {
95
+ code,
96
+ message,
97
+ data
98
+ }
99
+ });
100
+ }
101
+ };
102
+
103
+ // src/client.ts
104
+ var FhirflyClient = class {
105
+ config;
106
+ constructor(config) {
107
+ this.config = config;
108
+ }
109
+ /**
110
+ * Send a JSON-RPC request to the FHIRfly MCP endpoint
111
+ */
112
+ async request(method, params) {
113
+ const requestBody = {
114
+ jsonrpc: "2.0",
115
+ id: Date.now(),
116
+ method,
117
+ params
118
+ };
119
+ if (this.config.debug) {
120
+ console.error(`[MCP DEBUG] API Request: ${method}`, params);
121
+ }
122
+ try {
123
+ const response = await fetch(`${this.config.apiUrl}/mcp`, {
124
+ method: "POST",
125
+ headers: {
126
+ "Content-Type": "application/json",
127
+ "x-api-key": this.config.apiKey,
128
+ "User-Agent": "@fhirfly-io/mcp-server"
129
+ },
130
+ body: JSON.stringify(requestBody)
131
+ });
132
+ if (!response.ok) {
133
+ if (response.status === 401) {
134
+ return {
135
+ jsonrpc: "2.0",
136
+ id: requestBody.id,
137
+ error: {
138
+ code: -32001,
139
+ message: "Authentication failed. Check your FHIRFLY_API_KEY."
140
+ }
141
+ };
142
+ }
143
+ if (response.status === 429) {
144
+ return {
145
+ jsonrpc: "2.0",
146
+ id: requestBody.id,
147
+ error: {
148
+ code: -32002,
149
+ message: "Rate limit exceeded. Please slow down requests."
150
+ }
151
+ };
152
+ }
153
+ return {
154
+ jsonrpc: "2.0",
155
+ id: requestBody.id,
156
+ error: {
157
+ code: -32e3,
158
+ message: `API error: ${response.status} ${response.statusText}`
159
+ }
160
+ };
161
+ }
162
+ const result = await response.json();
163
+ if (this.config.debug) {
164
+ console.error("[MCP DEBUG] API Response:", JSON.stringify(result, null, 2));
165
+ }
166
+ return result;
167
+ } catch (error) {
168
+ const message = error instanceof Error ? error.message : String(error);
169
+ if (this.config.debug) {
170
+ console.error("[MCP DEBUG] API Error:", message);
171
+ }
172
+ return {
173
+ jsonrpc: "2.0",
174
+ id: requestBody.id,
175
+ error: {
176
+ code: -32003,
177
+ message: `Network error: ${message}`
178
+ }
179
+ };
180
+ }
181
+ }
182
+ /**
183
+ * Get list of available tools from FHIRfly
184
+ */
185
+ async listTools() {
186
+ const response = await this.request("tools/list", {});
187
+ if (response.error) {
188
+ throw new Error(response.error.message);
189
+ }
190
+ return response.result;
191
+ }
192
+ /**
193
+ * Call a tool on the FHIRfly API
194
+ */
195
+ async callTool(name, args) {
196
+ const response = await this.request("tools/call", {
197
+ name,
198
+ arguments: args
199
+ });
200
+ if (response.error) {
201
+ return {
202
+ content: [
203
+ {
204
+ type: "text",
205
+ text: JSON.stringify({
206
+ error: response.error.message,
207
+ code: response.error.code
208
+ })
209
+ }
210
+ ],
211
+ isError: true
212
+ };
213
+ }
214
+ return response.result;
215
+ }
216
+ };
217
+
218
+ // src/server.ts
219
+ var MCP_ERRORS = {
220
+ PARSE_ERROR: -32700,
221
+ INVALID_REQUEST: -32600,
222
+ METHOD_NOT_FOUND: -32601,
223
+ INVALID_PARAMS: -32602,
224
+ INTERNAL_ERROR: -32603
225
+ };
226
+ var SERVER_INFO = {
227
+ name: "fhirfly-mcp-server",
228
+ version: "0.1.0"
229
+ };
230
+ var SERVER_CAPABILITIES = {
231
+ tools: {}
232
+ };
233
+ var McpServer = class {
234
+ transport;
235
+ client;
236
+ config;
237
+ initialized = false;
238
+ constructor(config) {
239
+ this.config = config;
240
+ this.transport = new StdioTransport(config.debug);
241
+ this.client = new FhirflyClient(config);
242
+ }
243
+ /**
244
+ * Start the MCP server
245
+ */
246
+ start() {
247
+ if (this.config.debug) {
248
+ console.error("[MCP DEBUG] Starting FHIRfly MCP Server");
249
+ console.error("[MCP DEBUG] API URL:", this.config.apiUrl);
250
+ console.error("[MCP DEBUG] API Key:", this.config.apiKey.slice(0, 10) + "...");
251
+ }
252
+ this.transport.setHandler(this.handleMessage.bind(this));
253
+ this.transport.start();
254
+ }
255
+ /**
256
+ * Handle incoming JSON-RPC messages
257
+ */
258
+ async handleMessage(request) {
259
+ try {
260
+ if (request.jsonrpc !== "2.0" || !request.method) {
261
+ return {
262
+ jsonrpc: "2.0",
263
+ id: request.id ?? null,
264
+ error: {
265
+ code: MCP_ERRORS.INVALID_REQUEST,
266
+ message: "Invalid JSON-RPC request"
267
+ }
268
+ };
269
+ }
270
+ switch (request.method) {
271
+ case "initialize":
272
+ return this.handleInitialize(request);
273
+ case "initialized":
274
+ this.initialized = true;
275
+ return {
276
+ jsonrpc: "2.0",
277
+ id: request.id,
278
+ result: {}
279
+ };
280
+ case "tools/list":
281
+ return this.handleToolsList(request);
282
+ case "tools/call":
283
+ return this.handleToolsCall(request);
284
+ case "ping":
285
+ return {
286
+ jsonrpc: "2.0",
287
+ id: request.id,
288
+ result: {}
289
+ };
290
+ default:
291
+ return {
292
+ jsonrpc: "2.0",
293
+ id: request.id,
294
+ error: {
295
+ code: MCP_ERRORS.METHOD_NOT_FOUND,
296
+ message: `Unknown method: ${request.method}`
297
+ }
298
+ };
299
+ }
300
+ } catch (error) {
301
+ const message = error instanceof Error ? error.message : String(error);
302
+ if (this.config.debug) {
303
+ console.error("[MCP DEBUG] Handler error:", message);
304
+ }
305
+ return {
306
+ jsonrpc: "2.0",
307
+ id: request.id,
308
+ error: {
309
+ code: MCP_ERRORS.INTERNAL_ERROR,
310
+ message: `Internal error: ${message}`
311
+ }
312
+ };
313
+ }
314
+ }
315
+ /**
316
+ * Handle initialize request
317
+ */
318
+ async handleInitialize(request) {
319
+ if (this.config.debug) {
320
+ console.error("[MCP DEBUG] Initialize request from client");
321
+ }
322
+ return {
323
+ jsonrpc: "2.0",
324
+ id: request.id,
325
+ result: {
326
+ protocolVersion: "2024-11-05",
327
+ serverInfo: SERVER_INFO,
328
+ capabilities: SERVER_CAPABILITIES
329
+ }
330
+ };
331
+ }
332
+ /**
333
+ * Handle tools/list request
334
+ */
335
+ async handleToolsList(request) {
336
+ try {
337
+ const result = await this.client.listTools();
338
+ return {
339
+ jsonrpc: "2.0",
340
+ id: request.id,
341
+ result
342
+ };
343
+ } catch (error) {
344
+ const message = error instanceof Error ? error.message : String(error);
345
+ return {
346
+ jsonrpc: "2.0",
347
+ id: request.id,
348
+ error: {
349
+ code: MCP_ERRORS.INTERNAL_ERROR,
350
+ message: `Failed to list tools: ${message}`
351
+ }
352
+ };
353
+ }
354
+ }
355
+ /**
356
+ * Handle tools/call request
357
+ */
358
+ async handleToolsCall(request) {
359
+ const params = request.params;
360
+ if (!params?.name) {
361
+ return {
362
+ jsonrpc: "2.0",
363
+ id: request.id,
364
+ error: {
365
+ code: MCP_ERRORS.INVALID_PARAMS,
366
+ message: "Missing tool name in params"
367
+ }
368
+ };
369
+ }
370
+ try {
371
+ const result = await this.client.callTool(params.name, params.arguments ?? {});
372
+ return {
373
+ jsonrpc: "2.0",
374
+ id: request.id,
375
+ result
376
+ };
377
+ } catch (error) {
378
+ const message = error instanceof Error ? error.message : String(error);
379
+ return {
380
+ jsonrpc: "2.0",
381
+ id: request.id,
382
+ error: {
383
+ code: MCP_ERRORS.INTERNAL_ERROR,
384
+ message: `Tool call failed: ${message}`
385
+ }
386
+ };
387
+ }
388
+ }
389
+ };
390
+
391
+ // src/cli.ts
392
+ var API_KEY = process.env.FHIRFLY_API_KEY;
393
+ var API_URL = process.env.FHIRFLY_API_URL || "https://api.fhirfly.io";
394
+ var DEBUG = process.env.FHIRFLY_DEBUG === "1" || process.env.FHIRFLY_DEBUG === "true";
395
+ if (!API_KEY) {
396
+ console.error("Error: FHIRFLY_API_KEY environment variable is required");
397
+ console.error("");
398
+ console.error("To get an API key:");
399
+ console.error(" 1. Sign up at https://fhirfly.io");
400
+ console.error(" 2. Go to Dashboard > Credentials");
401
+ console.error(" 3. Create an MCP credential");
402
+ console.error("");
403
+ console.error("Then set the environment variable:");
404
+ console.error(' export FHIRFLY_API_KEY="your_api_key_here"');
405
+ console.error("");
406
+ console.error("Or configure in Claude Desktop's claude_desktop_config.json");
407
+ process.exit(1);
408
+ }
409
+ if (!API_KEY.startsWith("ffly_")) {
410
+ console.error("Error: Invalid API key format");
411
+ console.error("FHIRfly API keys start with 'ffly_'");
412
+ console.error("");
413
+ console.error("Please check your FHIRFLY_API_KEY environment variable.");
414
+ process.exit(1);
415
+ }
416
+ if (DEBUG) {
417
+ console.error("=".repeat(50));
418
+ console.error("FHIRfly MCP Server - Debug Mode");
419
+ console.error("=".repeat(50));
420
+ console.error("API URL:", API_URL);
421
+ console.error("API Key:", API_KEY.slice(0, 15) + "...");
422
+ console.error("=".repeat(50));
423
+ }
424
+ var server = new McpServer({
425
+ apiKey: API_KEY,
426
+ apiUrl: API_URL,
427
+ debug: DEBUG
428
+ });
429
+ server.start();
430
+ //# sourceMappingURL=cli.js.map
431
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/transport.ts","../src/client.ts","../src/server.ts","../src/cli.ts"],"names":[],"mappings":"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","file":"cli.js","sourcesContent":["/**\n * MCP Stdio Transport\n * Handles JSON-RPC communication over stdin/stdout\n */\n\nimport { createInterface } from \"readline\";\nimport type { JsonRpcRequest, JsonRpcResponse } from \"./types.js\";\n\nexport type MessageHandler = (request: JsonRpcRequest) => Promise<JsonRpcResponse>;\n\nexport class StdioTransport {\n private handler: MessageHandler | null = null;\n private debug: boolean;\n private pendingRequests: number = 0;\n private stdinClosed: boolean = false;\n\n constructor(debug: boolean = false) {\n this.debug = debug;\n }\n\n /**\n * Set the handler for incoming messages\n */\n setHandler(handler: MessageHandler): void {\n this.handler = handler;\n }\n\n /**\n * Start listening for messages on stdin\n */\n start(): void {\n const rl = createInterface({\n input: process.stdin,\n output: process.stdout,\n terminal: false,\n });\n\n // Buffer for accumulating partial messages\n let buffer = \"\";\n\n rl.on(\"line\", async (line) => {\n buffer += line;\n\n // Try to parse as JSON\n try {\n const request = JSON.parse(buffer) as JsonRpcRequest;\n buffer = \"\"; // Clear buffer on successful parse\n\n if (this.debug) {\n console.error(\"[MCP DEBUG] Received:\", JSON.stringify(request, null, 2));\n }\n\n if (this.handler) {\n this.pendingRequests++;\n try {\n const response = await this.handler(request);\n this.send(response);\n } finally {\n this.pendingRequests--;\n this.maybeExit();\n }\n }\n } catch {\n // If parse fails, might be partial message - keep buffering\n // Unless it looks like a complete but invalid message\n if (line.trim().endsWith(\"}\")) {\n this.sendError(null, -32700, \"Parse error: Invalid JSON\");\n buffer = \"\";\n }\n }\n });\n\n rl.on(\"close\", () => {\n this.stdinClosed = true;\n if (this.debug) {\n console.error(\"[MCP DEBUG] stdin closed, waiting for pending requests...\");\n }\n this.maybeExit();\n });\n\n // Handle errors gracefully\n process.stdin.on(\"error\", (err) => {\n if (this.debug) {\n console.error(\"[MCP DEBUG] stdin error:\", err.message);\n }\n });\n }\n\n /**\n * Exit if stdin is closed and no pending requests\n */\n private maybeExit(): void {\n if (this.stdinClosed && this.pendingRequests === 0) {\n if (this.debug) {\n console.error(\"[MCP DEBUG] All requests complete, exiting\");\n }\n process.exit(0);\n }\n }\n\n /**\n * Send a JSON-RPC response to stdout\n */\n send(response: JsonRpcResponse): void {\n const message = JSON.stringify(response);\n\n if (this.debug) {\n console.error(\"[MCP DEBUG] Sending:\", JSON.stringify(response, null, 2));\n }\n\n // Write to stdout with newline\n process.stdout.write(message + \"\\n\");\n }\n\n /**\n * Send an error response\n */\n sendError(id: string | number | null, code: number, message: string, data?: unknown): void {\n this.send({\n jsonrpc: \"2.0\",\n id,\n error: {\n code,\n message,\n data,\n },\n });\n }\n}\n","/**\n * FHIRfly API Client\n * Makes HTTP requests to the FHIRfly MCP endpoint\n */\n\nimport type {\n JsonRpcRequest,\n JsonRpcResponse,\n McpServerConfig,\n McpToolsListResult,\n McpToolCallResult,\n} from \"./types.js\";\n\nexport class FhirflyClient {\n private config: McpServerConfig;\n\n constructor(config: McpServerConfig) {\n this.config = config;\n }\n\n /**\n * Send a JSON-RPC request to the FHIRfly MCP endpoint\n */\n async request(method: string, params?: Record<string, unknown>): Promise<JsonRpcResponse> {\n const requestBody: JsonRpcRequest = {\n jsonrpc: \"2.0\",\n id: Date.now(),\n method,\n params,\n };\n\n if (this.config.debug) {\n console.error(`[MCP DEBUG] API Request: ${method}`, params);\n }\n\n try {\n const response = await fetch(`${this.config.apiUrl}/mcp`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": this.config.apiKey,\n \"User-Agent\": \"@fhirfly-io/mcp-server\",\n },\n body: JSON.stringify(requestBody),\n });\n\n if (!response.ok) {\n // Handle HTTP errors\n if (response.status === 401) {\n return {\n jsonrpc: \"2.0\",\n id: requestBody.id,\n error: {\n code: -32001,\n message: \"Authentication failed. Check your FHIRFLY_API_KEY.\",\n },\n };\n }\n\n if (response.status === 429) {\n return {\n jsonrpc: \"2.0\",\n id: requestBody.id,\n error: {\n code: -32002,\n message: \"Rate limit exceeded. Please slow down requests.\",\n },\n };\n }\n\n return {\n jsonrpc: \"2.0\",\n id: requestBody.id,\n error: {\n code: -32000,\n message: `API error: ${response.status} ${response.statusText}`,\n },\n };\n }\n\n const result = (await response.json()) as JsonRpcResponse;\n\n if (this.config.debug) {\n console.error(\"[MCP DEBUG] API Response:\", JSON.stringify(result, null, 2));\n }\n\n return result;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n\n if (this.config.debug) {\n console.error(\"[MCP DEBUG] API Error:\", message);\n }\n\n return {\n jsonrpc: \"2.0\",\n id: requestBody.id,\n error: {\n code: -32003,\n message: `Network error: ${message}`,\n },\n };\n }\n }\n\n /**\n * Get list of available tools from FHIRfly\n */\n async listTools(): Promise<McpToolsListResult> {\n const response = await this.request(\"tools/list\", {});\n\n if (response.error) {\n throw new Error(response.error.message);\n }\n\n return response.result as McpToolsListResult;\n }\n\n /**\n * Call a tool on the FHIRfly API\n */\n async callTool(name: string, args: Record<string, unknown>): Promise<McpToolCallResult> {\n const response = await this.request(\"tools/call\", {\n name,\n arguments: args,\n });\n\n if (response.error) {\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify({\n error: response.error.message,\n code: response.error.code,\n }),\n },\n ],\n isError: true,\n };\n }\n\n return response.result as McpToolCallResult;\n }\n}\n","/**\n * FHIRfly MCP Server\n * Main server class that handles MCP protocol messages\n */\n\nimport { StdioTransport } from \"./transport.js\";\nimport { FhirflyClient } from \"./client.js\";\nimport type {\n JsonRpcRequest,\n JsonRpcResponse,\n McpServerConfig,\n McpToolCallParams,\n} from \"./types.js\";\n\nconst MCP_ERRORS = {\n PARSE_ERROR: -32700,\n INVALID_REQUEST: -32600,\n METHOD_NOT_FOUND: -32601,\n INVALID_PARAMS: -32602,\n INTERNAL_ERROR: -32603,\n} as const;\n\n// Server capabilities\nconst SERVER_INFO = {\n name: \"fhirfly-mcp-server\",\n version: \"0.1.0\",\n};\n\nconst SERVER_CAPABILITIES = {\n tools: {},\n};\n\nexport class McpServer {\n private transport: StdioTransport;\n private client: FhirflyClient;\n private config: McpServerConfig;\n public initialized: boolean = false;\n\n constructor(config: McpServerConfig) {\n this.config = config;\n this.transport = new StdioTransport(config.debug);\n this.client = new FhirflyClient(config);\n }\n\n /**\n * Start the MCP server\n */\n start(): void {\n if (this.config.debug) {\n console.error(\"[MCP DEBUG] Starting FHIRfly MCP Server\");\n console.error(\"[MCP DEBUG] API URL:\", this.config.apiUrl);\n console.error(\"[MCP DEBUG] API Key:\", this.config.apiKey.slice(0, 10) + \"...\");\n }\n\n this.transport.setHandler(this.handleMessage.bind(this));\n this.transport.start();\n }\n\n /**\n * Handle incoming JSON-RPC messages\n */\n private async handleMessage(request: JsonRpcRequest): Promise<JsonRpcResponse> {\n try {\n // Validate JSON-RPC request structure\n if (request.jsonrpc !== \"2.0\" || !request.method) {\n return {\n jsonrpc: \"2.0\",\n id: request.id ?? null,\n error: {\n code: MCP_ERRORS.INVALID_REQUEST,\n message: \"Invalid JSON-RPC request\",\n },\n };\n }\n\n // Route to appropriate handler\n switch (request.method) {\n case \"initialize\":\n return this.handleInitialize(request);\n\n case \"initialized\":\n // Client notification that initialization is complete\n this.initialized = true;\n return {\n jsonrpc: \"2.0\",\n id: request.id,\n result: {},\n };\n\n case \"tools/list\":\n return this.handleToolsList(request);\n\n case \"tools/call\":\n return this.handleToolsCall(request);\n\n case \"ping\":\n return {\n jsonrpc: \"2.0\",\n id: request.id,\n result: {},\n };\n\n default:\n return {\n jsonrpc: \"2.0\",\n id: request.id,\n error: {\n code: MCP_ERRORS.METHOD_NOT_FOUND,\n message: `Unknown method: ${request.method}`,\n },\n };\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n\n if (this.config.debug) {\n console.error(\"[MCP DEBUG] Handler error:\", message);\n }\n\n return {\n jsonrpc: \"2.0\",\n id: request.id,\n error: {\n code: MCP_ERRORS.INTERNAL_ERROR,\n message: `Internal error: ${message}`,\n },\n };\n }\n }\n\n /**\n * Handle initialize request\n */\n private async handleInitialize(request: JsonRpcRequest): Promise<JsonRpcResponse> {\n if (this.config.debug) {\n console.error(\"[MCP DEBUG] Initialize request from client\");\n }\n\n return {\n jsonrpc: \"2.0\",\n id: request.id,\n result: {\n protocolVersion: \"2024-11-05\",\n serverInfo: SERVER_INFO,\n capabilities: SERVER_CAPABILITIES,\n },\n };\n }\n\n /**\n * Handle tools/list request\n */\n private async handleToolsList(request: JsonRpcRequest): Promise<JsonRpcResponse> {\n try {\n const result = await this.client.listTools();\n\n return {\n jsonrpc: \"2.0\",\n id: request.id,\n result,\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n\n return {\n jsonrpc: \"2.0\",\n id: request.id,\n error: {\n code: MCP_ERRORS.INTERNAL_ERROR,\n message: `Failed to list tools: ${message}`,\n },\n };\n }\n }\n\n /**\n * Handle tools/call request\n */\n private async handleToolsCall(request: JsonRpcRequest): Promise<JsonRpcResponse> {\n const params = request.params as McpToolCallParams | undefined;\n\n if (!params?.name) {\n return {\n jsonrpc: \"2.0\",\n id: request.id,\n error: {\n code: MCP_ERRORS.INVALID_PARAMS,\n message: \"Missing tool name in params\",\n },\n };\n }\n\n try {\n const result = await this.client.callTool(params.name, params.arguments ?? {});\n\n return {\n jsonrpc: \"2.0\",\n id: request.id,\n result,\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n\n return {\n jsonrpc: \"2.0\",\n id: request.id,\n error: {\n code: MCP_ERRORS.INTERNAL_ERROR,\n message: `Tool call failed: ${message}`,\n },\n };\n }\n }\n}\n","/**\n * FHIRfly MCP Server CLI\n * Entry point for running as an MCP server\n */\n\nimport { McpServer } from \"./server.js\";\n\n// Configuration from environment\nconst API_KEY = process.env.FHIRFLY_API_KEY;\nconst API_URL = process.env.FHIRFLY_API_URL || \"https://api.fhirfly.io\";\nconst DEBUG = process.env.FHIRFLY_DEBUG === \"1\" || process.env.FHIRFLY_DEBUG === \"true\";\n\n// Validate required configuration\nif (!API_KEY) {\n console.error(\"Error: FHIRFLY_API_KEY environment variable is required\");\n console.error(\"\");\n console.error(\"To get an API key:\");\n console.error(\" 1. Sign up at https://fhirfly.io\");\n console.error(\" 2. Go to Dashboard > Credentials\");\n console.error(\" 3. Create an MCP credential\");\n console.error(\"\");\n console.error(\"Then set the environment variable:\");\n console.error(' export FHIRFLY_API_KEY=\"your_api_key_here\"');\n console.error(\"\");\n console.error(\"Or configure in Claude Desktop's claude_desktop_config.json\");\n process.exit(1);\n}\n\n// Validate API key format\nif (!API_KEY.startsWith(\"ffly_\")) {\n console.error(\"Error: Invalid API key format\");\n console.error(\"FHIRfly API keys start with 'ffly_'\");\n console.error(\"\");\n console.error(\"Please check your FHIRFLY_API_KEY environment variable.\");\n process.exit(1);\n}\n\nif (DEBUG) {\n console.error(\"=\".repeat(50));\n console.error(\"FHIRfly MCP Server - Debug Mode\");\n console.error(\"=\".repeat(50));\n console.error(\"API URL:\", API_URL);\n console.error(\"API Key:\", API_KEY.slice(0, 15) + \"...\");\n console.error(\"=\".repeat(50));\n}\n\n// Create and start server\nconst server = new McpServer({\n apiKey: API_KEY,\n apiUrl: API_URL,\n debug: DEBUG,\n});\n\nserver.start();\n"]}