feat(agent): agent-native wave phases 2+3 — core surface, instance registry, devframe connect - #145
Open
antfubot wants to merge 4 commits into
Open
feat(agent): agent-native wave phases 2+3 — core surface, instance registry, devframe connect#145antfubot wants to merge 4 commits into
antfubot wants to merge 4 commits into
Conversation
…ommands bridge, git agent tools - createMcpFetchHandler: framework-agnostic web-standard MCP endpoint extracted from mountMcpHttp (now a thin h3 wrapper); exported from devframe/adapters/mcp for custom hosts (Next App Router, etc.) - built-in read_state(key?) MCP tool over shared state, honoring the exposeSharedState filter alongside the resource projection - hub commands gain opt-in agent exposure: agent field (description, safety, valibot args) projects handler-bearing commands into ctx.agent; DF8404 rejects agent exposure on group-only commands - valibot→JSON-Schema conversion moved to devframe/utils/valibot-json-schema (public) so SDK-free hosts can convert schemas - rpc: schema-typed handlers may be async — Thenable<InferReturnType<RS>> in the schema-typed definition branch - git plugin: status/log/show/branches/diff agent-flagged with valibot args/returns schemas (read-only surface; writes stay private) - docs: hub commands-as-tools, read_state, custom-host mounting; DF8404 page
…connect, in-process Next MCP - instance registry: registerDevframeInstance/readDevframeInstances/ probeDevframeInstance/listLiveDevframeInstances in devframe/node — atomic same-dir writes, prune-on-read, ghost dedup per (port, basePath), dialable-origin adoption for family-ambiguous localhost binds; createDevServer registers automatically and unregisters on close; DEVFRAME_INSTANCES_DIR / DEVFRAME_DISABLE_INSTANCE_REGISTRY overrides - first devframe bin: `devframe connect` runs the stdio MCP connector — devframe_index (discover instances + their tools, funnel hints for MCP-less servers) and devframe_call (proxy one tool call over Streamable-HTTP); errors carry actionable fix payloads; missing SDK peer throws coded DF0043 - @devframes/next: DevframeNextHost.mountMcp serves MCP in-process on the Next app's own origin (the /_next/mcp shape); hub example wires it, advertises it in connection meta, registers the instance, and agent-flags its ping command; catch-all route exports POST/DELETE - mcp adapter: drop non-object outputSchema projections (MCP requires type object; a v.void() returns schema broke SDK clients) - e2e: devframe-connect (files-inspector round-trip incl. gateway tool) and minimal-next-devframe-hub (in-process discovery + command call); hermetic per-suite registries; vitest keeps unit runs out of the global registry - diagnostics DF0042/DF0043 + docs pages; connect/registry docs in the MCP adapter page
- ctx.agent.registerToolProvider(() => AgentToolInput[]): a lazy tool source queried at list/getTool/invoke time — the same on-demand projection applied to agent-flagged RPCs; earlier sources win on id collision; handle.notifyChanged() drives tools/list_changed - hub commands host derives its agent projection through one provider: the commands map is the single source of truth, replacing the registerAgentTools/unregisterAgentTools mirror and its handle map - built-in and connector tool names follow the devframe:<area>:<fn> convention: read_state -> devframe:state:read, devframe_index -> devframe:connect:list-instances, devframe_call -> devframe:connect:call-tool
Collaborator
Author
|
Follow-up commit
Gates rerun: 905 unit tests, typecheck, lint, and the three connector e2e specs all green. (tsnapi flagged the removed bridge methods as a narrowing — allowed deliberately since they only ever existed in this unmerged stack.) |
antfubot
changed the base branch from
feat/agent-mcp-wave-phase-2
to
feat/agent-mcp-wave-phase-1
July 29, 2026 08:39
- drop the devframe/utils/valibot-json-schema subpath: AgentToolInput gains valibot args (the same shape RPC definitions carry); the agent host derives the JSON-Schema input internally, and the hub passes schemas through untouched — conversion is an implementation detail again - devframe/node exports only registerDevframeInstance (+ its two types) from the instance registry; the read/probe/prune helpers stay internal to the connector
Collaborator
Author
|
Follow-up commit
Gates rerun: 905 unit tests (incl. new |
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.
Why
Phases 2 and 3 of plan 031 (stacked on #142; supersedes #144, folded in here). Phase 2 builds the core agent surface the wave needs; phase 3 ships the flagship: the connector half of the architecture next-devtools-mcp validated. Vercel hand-rolled ~14 KB of Next-specific port/process discovery; devframe owns the framework, so dev servers announce themselves and one generic connector serves every devframe-built tool.
Phase 2 — core surface
createMcpFetchHandler(ctx, options)— the MCP Streamable-HTTP endpoint as a framework-agnostic web-standardRequest → Responsehandler (sessions, origin gate, teardown).mountMcpHttpis now a thin h3 wrapper over it.devframe:state:readtool — tool-shaped shared-state access (no key → key list, key → JSON value), honoring the sameexposeSharedStatefilter as the resource projection. Many MCP clients only consume tools; resources stay for those that don't.ctx.agent.registerToolProvider(() => AgentToolInput[]): a tool source queried atlist/getTool/invoketime, the same on-demand projection the agent host applies toagent-flagged RPCs. The commands host registers one provider deriving tools from its commands map — single source of truth, no mirrored registrations. Commands opt in via anagentfield (description-as-prompt,safety, optional positional valibotargs, single object unwrapped);agenton a handler-less group throws DF8404; the field never crosses the wire.notifyChanged()drivestools/list_changed.devframe/utils/valibot-json-schema— the valibot→JSON-Schema conversion promoted to a public util so SDK-free hosts can convert schemas.Thenable<InferReturnType<RS>>(explicitRS⇒ no inference risk; sync handlers stay assignable). Unblocks schema-typing genuinely-async RPCs — the limitation plan 001 hit.status/log/show/branches/diffagent-flagged with args/returns schemas (safety: 'read'). Write ops stay agent-invisible. Cross-refs plan 029.Phase 3 — instance registry, connector, in-process Next MCP
devframe/node):registerDevframeInstancewrites an atomic record to~/.devframe/instances/<pid>-<port>.json; readers prune dead records on failed__connection.jsonprobes, dedup same-port ghosts (newest wins), and adopt a dialable origin for family-ambiguouslocalhostbinds.createDevServerregisters automatically (CLI dev, viteDevBridge, the Next handler side-car) and unregisters on close; in-process hosts call it explicitly.DEVFRAME_INSTANCES_DIR/DEVFRAME_DISABLE_INSTANCE_REGISTRYoverride. Failures degrade to coded warnings (DF0042).devframebin +connect— the package's first bin.devframe connectruns a stdio MCP connector exposing two gateway tools:devframe:connect:list-instances(discover live instances + list their MCP tools; MCP-less instances carry a restart-with---mcpfunnel hint) anddevframe:connect:call-tool(proxy one tool call over Streamable-HTTP). Errors carry{ message, fix }payloads; a missing SDK peer throws DF0043.--portprobes beside the registry.DevframeNextHost.mountMcp(ctx, path)serves the fetch handler on the Next app's own origin: the literal/_next/mcpshape on devframe primitives. The hub example mounts/__hub/__mcp, advertises it in its connection meta, registers the instance, and agent-flags its ping command; the catch-all route exports POST/DELETE (MCP methods).outputSchemaprojections are dropped (av.void()returns schema producedtype: \"null\", which SDK clients reject ontools/list).devframe-connect.spec.ts(files-inspector: discovery → gateway-tool round-trip → actionable error payloads) andminimal-next-devframe-hub-dev.spec.ts(connector discovers the hub inside the Next dev server and calls its agent-flagged command through the in-process endpoint). Hermetic per-suite registry dirs; unit runs stay out of the global registry.All tool names follow the
devframe:<area>:<fn>convention, matching the built-in RPC families.Verification
Full gate:
pnpm lint && pnpm test && pnpm typecheck && pnpm build— 905 unit tests (provider laziness/collision/notify semantics, registry atomicity/dedup/prune, outputSchema guard, commands bridge against the real agent host) and 17/17 Playwright e2e including both connector gates.This PR was created with the help of an agent.