Thanks for building this — the LCSC-to-KiCad conversion is just what I need.
One thing I noticed while evaluating it, in packages/mcp/src/index.ts:
async function main() {
const registration = await ensureGlobalLibraryTables();
if (!registration.success) {
process.exit(1);
}
const httpPort = startHttpServer();
...
}
The server writes KiCad's global sym-lib-table and fp-lib-table before any tool is called. MCP hosts start servers speculatively — on session start, in every project, whether or not the user touches them. So merely having jlc-mcp in an MCP config mutates machine-global KiCad configuration that affects every project on the box, not just the one being worked on. For users with a deliberate library layout (shared repo-relative libraries, ${KIPRJMOD} paths) that's a surprising thing to have happen unasked.
The sharper problem is the process.exit(1). If the tables aren't writable, or the KiCad version isn't detected, the server doesn't start at all — so component_search, which is read-only and needs no libraries, becomes unavailable because of a filesystem write it never uses. A read path is gated behind an unrelated write.
Smaller version of the same thing: startHttpServer() binds a port unconditionally for the browser UI, so a user who only wants stdio tool calls gets a listening socket they didn't ask for.
Suggested fixes, roughly in order of value
- Make registration lazy — call
ensureGlobalLibraryTables() on first library_* invocation rather than in main(). No new config surface, and search-only users never touch the tables.
- Degrade instead of exiting — on failure, log and disable the
library_* tools, but keep serving component_search.
- Add a
--read-only mode that omits the five writing tools from the advertised tool list entirely. That's a stronger guarantee than skipping startup work, since a model can't call a tool that isn't listed — useful for anyone wanting sourcing lookups without granting write access to their KiCad libraries.
- Same treatment for the HTTP server —
--no-http, or start it lazily.
(1) and (2) alone would resolve it for me; (3) is the nice-to-have.
I'm happy to offer a PR for any subset of these if you'd welcome it. Just say which shape you'd prefer before I write anything, since the work spans packages/core and packages/mcp. Per your project protocol, I would include a changeset.
Unrelated: LICENSE file issue
package.json declares MIT, but there's no LICENSE in the repo, so GitHub reports the license as unset. Would you consider adding one? It makes contributing unambiguous.
Thanks for building this — the LCSC-to-KiCad conversion is just what I need.
One thing I noticed while evaluating it, in
packages/mcp/src/index.ts:The server writes KiCad's global
sym-lib-tableandfp-lib-tablebefore any tool is called. MCP hosts start servers speculatively — on session start, in every project, whether or not the user touches them. So merely havingjlc-mcpin an MCP config mutates machine-global KiCad configuration that affects every project on the box, not just the one being worked on. For users with a deliberate library layout (shared repo-relative libraries,${KIPRJMOD}paths) that's a surprising thing to have happen unasked.The sharper problem is the
process.exit(1). If the tables aren't writable, or the KiCad version isn't detected, the server doesn't start at all — socomponent_search, which is read-only and needs no libraries, becomes unavailable because of a filesystem write it never uses. A read path is gated behind an unrelated write.Smaller version of the same thing:
startHttpServer()binds a port unconditionally for the browser UI, so a user who only wants stdio tool calls gets a listening socket they didn't ask for.Suggested fixes, roughly in order of value
ensureGlobalLibraryTables()on firstlibrary_*invocation rather than inmain(). No new config surface, and search-only users never touch the tables.library_*tools, but keep servingcomponent_search.--read-onlymode that omits the five writing tools from the advertised tool list entirely. That's a stronger guarantee than skipping startup work, since a model can't call a tool that isn't listed — useful for anyone wanting sourcing lookups without granting write access to their KiCad libraries.--no-http, or start it lazily.(1) and (2) alone would resolve it for me; (3) is the nice-to-have.
I'm happy to offer a PR for any subset of these if you'd welcome it. Just say which shape you'd prefer before I write anything, since the work spans
packages/coreandpackages/mcp. Per your project protocol, I would include a changeset.Unrelated: LICENSE file issue
package.jsondeclares MIT, but there's noLICENSEin the repo, so GitHub reports the license as unset. Would you consider adding one? It makes contributing unambiguous.