← back to Filemaker Mcp
bin/fm.js
45 lines
#!/usr/bin/env node
// Thin CLI over the FileMaker client — used to verify auth and discover layouts
// before/independent of the MCP server. Loads .env from the project root.
import { readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
import * as fm from '../src/fm-client.js';
const __dir = dirname(fileURLToPath(import.meta.url));
// minimal .env loader (no dep)
try {
for (const line of readFileSync(join(__dir, '..', '.env'), 'utf8').split('\n')) {
const m = line.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*)\s*$/);
if (m && !process.env[m[1]]) process.env[m[1]] = m[2].replace(/^["']|["']$/g, '');
}
} catch {}
const [cmd, ...args] = process.argv.slice(2);
const out = (o) => console.log(JSON.stringify(o, null, 2));
try {
switch (cmd) {
case 'ping': out(await fm.ping()); break;
case 'databases': out(fm.listDatabases()); break;
case 'layouts': out(await fm.layouts(args[0])); break;
case 'fields': out(await fm.fieldMetadata(args[0], args[1])); break;
case 'get': out(await fm.getRecord(args[0], args[1], args[2])); break;
case 'list': out(await fm.listRecords(args[0], args[1], { limit: Number(args[2]) || 20 })); break;
case 'find': out(await fm.findRecords(args[0], args[1], JSON.parse(args[2]))); break;
default:
console.error(`Usage:
fm ping
fm databases
fm layouts <db>
fm fields <db> <layout>
fm get <db> <layout> <recordId>
fm list <db> <layout> [limit]
fm find <db> <layout> '<json-query>'`);
process.exit(1);
}
} catch (e) {
console.error('ERROR:', e.message);
process.exit(1);
}