Skip to content

feat(connector-mcp): adopt MCP servers as connectors (ADR-0024)#1424

Merged
os-zhuang merged 2 commits into
mainfrom
claude/cool-knuth-aMIje
May 31, 2026
Merged

feat(connector-mcp): adopt MCP servers as connectors (ADR-0024)#1424
os-zhuang merged 2 commits into
mainfrom
claude/cool-knuth-aMIje

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Summary

Implements ADR-0024: ship @objectstack/connector-mcp, a single generic adapter that turns any Model Context Protocol (MCP) server into an ordinary type: 'api' connector on the automation engine — with no per-server code. One adapter unlocks the entire MCP ecosystem (filesystem, GitHub, Slack, databases, search, hundreds of community servers).

What's in the package

Mirrors the connector-rest / connector-slack conventions (Apache-2.0, tsup build, a create…Connector factory + a …Plugin).

  • createMcpConnector({ transport, include?, … }) — connects over stdio or streamable-HTTP, calls tools/list, and builds the Connector definition once. Each tool maps mechanically to an action (name → key, description → label/description, inputSchema → inputSchema); each handler closes over the tool name and dispatches to tools/call. Results normalise to the shared { ok, content, … } envelope — a logical tool error surfaces as ok: false rather than throwing, so a flow can branch on ${node.ok}.
  • ConnectorMcpPlugin — registers the connector through the existing engine.registerConnector() path (no new engine surface, no mcp_call node, no parallel registry — the anti-patterns ADR-0024 §5 rules out) and tears the MCP connection down on destroy(). Fail-soft: an unreachable server or a missing automation engine is logged and skipped.
  • After construction the registry, the connector_action node, the discovery route, and the Studio palette all see a plain connector — they never know it is MCP-backed (ADR-0024 §2).

Security posture (ADR-0024 §3)

Credentials live with the MCP server, not in ConnectorSchema. The operator-supplied transport env (stdio) / headers (http) are passed straight to the MCP client and kept out of the serialized, discovery-exposed def. The open tier runs an operator-provided server with operator-provided credentials; managed secrets, per-tenant lifecycle, and sandboxed stdio execution remain the enterprise tier (§4).

Implementation notes

  • The real MCP SDK client is lazily imported and injectable (clientFactory), mirroring connector-rest's fetchImpl — so unit tests stay hermetic and the SDK only loads when a real connection is made.
  • The Plugin lifecycle exposes destroy() (not stop()), so teardown is wired to destroy() to ensure the MCP connection / child process is actually released on shutdown.

Testing

  • pnpm build — ✅ ESM + CJS + DTS
  • pnpm exec tsc --noEmit — ✅ strict
  • pnpm test — ✅ 9 passing (discovery → action mapping, include allowlist, tools/call dispatch + result normalisation incl. isError, lifecycle/close, and an end-to-end flow through LiteKernel + the automation engine)

Follow-ups (out of scope, per ADR-0024)

  • A worked examples/ entry (reference filesystem / GitHub MCP server → allowlisted actions in a flow).
  • Wiring MCP-backed actions into the ADR-0011 AI-tool surface.

https://claude.ai/code/session_01G9v2WA48voVBSkQ7sjFkqC


Generated by Claude Code

Add @objectstack/connector-mcp — a single generic adapter that turns any
Model Context Protocol server into an ordinary type:'api' connector on the
automation engine, with no per-server code.

- createMcpConnector(): connect over stdio or streamable-HTTP, call
  tools/list, map each tool to a connector action (name→key,
  description→label/description, inputSchema→inputSchema), and dispatch
  connector_action calls to tools/call. Results normalise to the shared
  { ok, content, ... } envelope; logical tool errors surface as ok:false.
- ConnectorMcpPlugin: registers via the existing engine.registerConnector()
  path (no new engine surface, no mcp_call node) and tears the MCP connection
  down on destroy(). Fail-soft when the server or automation engine is absent.
- Credentials stay with the MCP server (transport env/headers), never in
  ConnectorSchema or the discovery-exposed def.
- Mirrors the connector-rest/connector-slack conventions; the real MCP SDK
  client is lazily imported and injectable so unit tests stay hermetic.

https://claude.ai/code/session_01G9v2WA48voVBSkQ7sjFkqC
@vercel

vercel Bot commented May 31, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment May 31, 2026 11:07pm

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation dependencies Pull requests that update a dependency file tests tooling size/l labels May 31, 2026
Keeps @objectstack/connector-mcp versioned in lockstep with the rest of the
public monorepo, satisfying scripts/check-changeset-fixed.mjs (the Validate
Package Dependencies CI gate).

https://claude.ai/code/session_01G9v2WA48voVBSkQ7sjFkqC
@os-zhuang
os-zhuang marked this pull request as ready for review May 31, 2026 23:05
@os-zhuang
os-zhuang merged commit 6e4b3f2 into main May 31, 2026
10 of 12 checks passed
Comment on lines +115 to +118
const slug = input
.toLowerCase()
.replace(/[^a-z0-9]+/g, '_')
.replace(/^_+|_+$/g, '');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation size/l tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants