openclaw - ✅(Solved) Fix Plugin SDK: add native registerMcpServer for managed MCP [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#57355Fetched 2026-04-08 01:50:42
View on GitHub
Comments
0
Participants
1
Timeline
1
Reactions
0
Participants
Timeline (top)
cross-referenced ×1

Add a native registerMcpServer surface to the plugin SDK so plugins can register managed stdio MCP servers and inject them into embedded OpenAI-backed runs.

Root Cause

Add a native registerMcpServer surface to the plugin SDK so plugins can register managed stdio MCP servers and inject them into embedded OpenAI-backed runs.

PR fix notes

PR #62160: Plugin SDK: register managed MCP servers

Description (problem / solution / changelog)

Summary

  • adds a native plugin SDK seam for registering managed MCP servers through api.registerMcpServer(...)
  • stores plugin-owned MCP registrations in the plugin registry and merges them into embedded MCP runtime config with deterministic precedence behavior
  • adds manifest-driven MCP ownership metadata for native and bundled plugin discovery/status surfaces
  • includes a hello-world native plugin fixture and runtime/test coverage for registration, loading, workspace scoping, and embedded MCP materialization

Change Type

  • Feature
  • Refactor required for the change
  • Bug fix
  • Docs
  • Security hardening
  • Chore/infra

Scope

  • Gateway / orchestration
  • API / contracts
  • Integrations
  • UI / DX
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • CI/CD / infra

Linked Issue/PR

  • Related #57355
  • This PR fixes a bug or regression

Root Cause

  • Root cause: N/A
  • Missing detection / guardrail: N/A
  • Contributing context (if known): N/A

Regression Test Plan

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file:
    • src/plugins/captured-registration.test.ts
    • src/plugins/loader.test.ts
    • src/plugins/mcp-servers.test.ts
    • src/plugins/status.test.ts
    • src/plugins/manifest.json5-tolerance.test.ts
    • src/agents/pi-bundle-mcp-runtime.test.ts
  • Scenario the test should lock in:
    • native plugins can register managed stdio MCP servers
    • manifest MCP ownership survives normalization/discovery
    • plugin MCP servers load with deterministic ordering and workspace scoping
    • embedded runtime materializes plugin MCP tools, including copied sandbox workspace cases
  • Why this is the smallest reliable guardrail:
    • the feature crosses SDK registration, manifest ingestion, registry loading, and embedded runtime materialization, so narrow unit coverage alone is not enough
  • Existing test that already covers this (if any): none before this change
  • If no new test is added, why not: N/A

User-visible / Behavior Changes

  • Native plugins can now register managed MCP servers that become available in embedded MCP-enabled runs.
  • Plugin status/inspect surfaces can report MCP server ownership.
  • Managed plugin MCP servers are stdio-only in this phase and remain lower precedence than user/operator MCP config entries with the same name.

Diagram

Before:
[native plugin register(api)] -> [providers/tools only] -> [no plugin-owned MCP server in embedded runtime]

After:
[native plugin register(api)] -> [registerMcpServer] -> [plugin registry + manifest ownership] -> [embedded MCP config merge] -> [plugin MCP tool available]

Security Impact

  • New permissions/capabilities? (Yes)
  • Secrets/tokens handling changed? (No)
  • New/changed network calls? (No)
  • Command/tool execution surface changed? (Yes)
  • Data access scope changed? (No)
  • If any Yes, explain risk + mitigation:
    • This adds a plugin capability to launch managed stdio MCP processes. The Phase 1 surface is constrained to validated stdio config, duplicate names are deterministic, and user/operator config still wins on conflicts.

Human Verification

  • Verified scenarios:
    • targeted MCP/plugin status, loader, manifest, and runtime tests on this branch
    • manual hello-world fixture install plus direct child-process startup validation after adding the MCP SDK runtime dependency
  • Edge cases checked:
    • duplicate-name handling
    • fail-closed workspace matching
    • copied sandbox workspace runtime path
    • trimming/skipping empty MCP names in status output
  • What I did not verify:
    • upstream CI is still pending on the latest pushed head

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? (Yes)
  • Config/env changes? (No)
  • Migration needed? (No)

Risks and Mitigations

  • Risk: plugin-owned MCP registration introduces a new execution surface
    • Mitigation: validation constrains the Phase 1 shape to managed stdio servers and embedded config precedence remains deterministic
  • Risk: registry/workspace mismatches could hide plugin MCP tools in sandboxed runs
    • Mitigation: added source-workspace-aware runtime coverage and fail-closed matching when the active workspace is unknown

Changed files

  • docs/.generated/plugin-sdk-api-baseline.sha256 (modified, +2/-2)
  • docs/plugins/building-plugins.md (modified, +25/-0)
  • docs/plugins/sdk-overview.md (modified, +1/-0)
  • extensions/memory-wiki/src/cli.test.ts (modified, +2/-2)
  • extensions/memory-wiki/src/query.test.ts (modified, +2/-2)
  • extensions/zalouser/src/channel.adapters.ts (modified, +7/-8)
  • src/agents/embedded-pi-mcp.ts (modified, +8/-1)
  • src/agents/pi-bundle-mcp-materialize.ts (modified, +2/-0)
  • src/agents/pi-bundle-mcp-runtime.test.ts (modified, +147/-0)
  • src/agents/pi-bundle-mcp-runtime.ts (modified, +7/-0)
  • src/agents/pi-bundle-mcp-types.ts (modified, +1/-0)
  • src/agents/pi-embedded-runner/compact.hooks.harness.ts (modified, +20/-5)
  • src/agents/pi-embedded-runner/compact.hooks.test.ts (modified, +26/-0)
  • src/agents/pi-embedded-runner/compact.ts (modified, +1/-0)
  • src/agents/pi-embedded-runner/run/attempt.ts (modified, +1/-0)
  • src/channels/plugins/acp-bindings.test.ts (modified, +3/-2)
  • src/gateway/server-plugins.test.ts (modified, +1/-0)
  • src/gateway/test-helpers.plugin-registry.ts (modified, +1/-0)
  • src/plugin-sdk/core.ts (modified, +2/-0)
  • src/plugin-sdk/plugin-entry.ts (modified, +4/-0)
  • src/plugins/api-builder.ts (modified, +3/-0)
  • src/plugins/bundled-capability-metadata.test.ts (modified, +2/-0)
  • src/plugins/bundled-capability-runtime.ts (modified, +11/-0)
  • src/plugins/captured-registration.test.ts (modified, +2/-0)
  • src/plugins/captured-registration.ts (modified, +7/-0)
  • src/plugins/contracts/inventory/bundled-capability-metadata.ts (modified, +3/-0)
  • src/plugins/contracts/plugin-sdk-package-contract-guardrails.test.ts (modified, +5/-1)
  • src/plugins/contracts/registry.contract.test.ts (modified, +15/-0)
  • src/plugins/contracts/registry.ts (modified, +8/-1)
  • src/plugins/loader.test.ts (modified, +73/-0)
  • src/plugins/loader.ts (modified, +10/-0)
  • src/plugins/manifest-registry.ts (modified, +2/-1)
  • src/plugins/manifest.json5-tolerance.test.ts (modified, +19/-0)
  • src/plugins/manifest.ts (modified, +3/-0)
  • src/plugins/mcp-servers.test.ts (added, +574/-0)
  • src/plugins/mcp-servers.ts (added, +220/-0)
  • src/plugins/registry-empty.ts (modified, +1/-0)
  • src/plugins/registry.ts (modified, +62/-0)
  • src/plugins/status.test-helpers.ts (modified, +3/-0)
  • src/plugins/status.test.ts (modified, +128/-5)
  • src/plugins/status.ts (modified, +90/-22)
  • src/plugins/types.ts (modified, +21/-0)
  • src/test-utils/channel-plugins.ts (modified, +1/-0)
  • test/fixtures/native-plugin-mcp-hello-world/hello-world.mjs (added, +21/-0)
  • test/fixtures/native-plugin-mcp-hello-world/index.ts (added, +17/-0)
  • test/fixtures/native-plugin-mcp-hello-world/openclaw.plugin.json (added, +12/-0)
  • test/fixtures/native-plugin-mcp-hello-world/package.json (added, +14/-0)
  • test/helpers/plugins/plugin-api.ts (modified, +1/-0)
RAW_BUFFERClick to expand / collapse

Summary

Add a native registerMcpServer surface to the plugin SDK so plugins can register managed stdio MCP servers and inject them into embedded OpenAI-backed runs.

Scope

  • add a typed managed-MCP registration contract to ClawdbotPluginApi
  • store managed MCP registrations in the plugin registry
  • resolve those registrations into embedded PI settings before session creation
  • verify the runtime with a hello-world MCP server that returns hello claw
  • attach a showboat proof for reproducible validation

Notes

  • This repo currently uses origin/main; origin/master does not exist.
  • The example implementation lives in /Users/kevinlin/.worktrees/openclaw/dev/kevinlin/chatgpt-apps-milestone-specs/, but the current branch needs a targeted backport to the older Clawdbot* plugin architecture.

Context

  • session: 019d3acd-acf1-7fe2-b106-11d24d223a83

extent analysis

Fix Plan

To add a native registerMcpServer surface to the plugin SDK, follow these steps:

  • Add a typed managed-MCP registration contract to ClawdbotPluginApi:
interface ManagedMcpRegistration {
  id: string;
  server: any; // MCP server implementation
}

interface ClawdbotPluginApi {
  registerMcpServer(registration: ManagedMcpRegistration): void;
}
  • Store managed MCP registrations in the plugin registry:
const pluginRegistry: { [id: string]: ManagedMcpRegistration } = {};

ClawdbotPluginApi.registerMcpServer = (registration: ManagedMcpRegistration) => {
  pluginRegistry[registration.id] = registration;
};
  • Resolve those registrations into embedded PI settings before session creation:
const resolveMcpRegistrations = () => {
  const piSettings: any[] = [];
  Object.values(pluginRegistry).forEach((registration) => {
    piSettings.push({
      id: registration.id,
      server: registration.server,
    });
  });
  return piSettings;
};
  • Implement a hello-world MCP server that returns hello claw:
const helloWorldMcpServer = {
  handleRequest: () => {
    return 'hello claw';
  },
};

ClawdbotPluginApi.registerMcpServer({
  id: 'hello-world',
  server: helloWorldMcpServer,
});

Verification

To verify the fix, create a test that registers an MCP server and checks if it's correctly injected into the embedded OpenAI-backed run:

it('registers MCP server', async () => {
  const testMcpServer = {
    handleRequest: () => {
      return 'test response';
    },
  };

  ClawdbotPluginApi.registerMcpServer({
    id: 'test',
    server: testMcpServer,
  });

  const piSettings = resolveMcpRegistrations();
  expect(piSettings.length).toBe(1);
  expect(piSettings[0].id).toBe('test');
  expect(piSettings[0].server).toBe(testMcpServer);
});

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING