feat(core): wire MCP servers into Environment via adapter layer - #216
Open
field-claw wants to merge 2 commits into
Open
feat(core): wire MCP servers into Environment via adapter layer#216field-claw wants to merge 2 commits into
field-claw wants to merge 2 commits into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
PenguinHarness declared
mcpServersin tool config but never connected them (the docs note "enumerating concrete MCP tools is reserved for a later adapter layer"). This PR implements that layer so configured MCP servers become real, LLM-callable tools.What changed
McpToolAdapter(packages/core/src/environment/mcp/client.ts): connects each declared stdio/SSE MCP server, enumerates tools, and wraps them asBuiltinToolinstances.mcp__<server>__<tool>(collision-safe).inputSchema(JSON Schema) passes straight intoToolDefinitionConfig.parameters— both areRecord<string,unknown>, no conversion layer.Environmentgains astatic async create(): whenmcpServersis non-empty it connects them and registers their tools. The sync constructor is preserved (callers without MCP are unaffected).agent.tsnow usesEnvironment.create()so the real agent loop can reach MCP tools.ToolExecutionContext.signalis forwarded into the SDKcallTooloptions.signal, so user-interrupt / Environment timeout cancels an in-flight MCP request.@modelcontextprotocol/sdk(MIT/Apache-2.0, license-compatible with Apache-2.0).Verification
pnpm --filter @prismshadow/penguin-core typecheck→ passes.test/mcp-client.test.ts→ 3/3 green (namespacing, inputSchema passthrough, BuiltinTool delegation, fault isolation).test/mcp-e2e.mts(spins up a live local stdio MCP server viatsx, drivesEnvironment.create → listTools → executeTool) → reaches and calls the tool, streams output, finalizescompleted.Backward compatibility
Callers that don't configure
mcpServerscontinue using the syncnew Environment(...)with zero changes. Only the runtime agent path switched toawait Environment.create(...).Notes / follow-ups (out of scope)
mcpServersnot added; JSON edit + docs suffices for now.ssetransport is wired inbuildTransport(client-sideSSEClientTransport) but is not covered by a live e2e — server-side SSE was removed from the MCP spec and the SDK'sSSEServerTransportis unstable to stand up as a test fixture. The stdio path is fully e2e-tested.signalis now forwarded intocallTool;Environmentcontinues to enforce timeout/abort on the tool stream as a backstop.Generated with Claude as a PenguinHarness MCP evaluation follow-up.