Skip to content

Config validation rejects any mcp.servers declaration for a route-generated server (AB4304/AB4322), though normalize supports env/args/targets/apps on it #380

Description

@ScriptedAlchemy

Summary

normalizeMcpServers (packages/agent-bundle/src/config/normalize.ts) explicitly merges a config-side declaration onto a route-generated server — const declaration = configured[name] ?? {} feeds env, args, and targets, and normalizeMcpApps reads rawServer.apps for any server with a source (generated servers have one) — but validateMcpServer / validateMcpApps (packages/agent-bundle/src/config/validate.ts) never consult the route graph. Any mcp.servers.<generated-server> declaration is therefore rejected before normalization runs:

  • a declaration with only env (or args/targets) → AB4304 "must define exactly one of entry, command, or url, or provide the conventional stdio entry src/mcp/.ts"
  • a declaration with appsAB4304 plus AB4322 "can declare Apps only with a local entry"

So there is no supported way to attach extra env/args/targets to a generated server, and the config-side apps record documented in docs/framework-mode.md / the mcp-app example is unusable for generated servers (the src/mcp/<server>/apps/*.ts route is the only working path). Neither docs/framework-mode.md, docs/entry-conventions.md, nor docs/diagnostics.md mention this restriction, and the AB4304 recovery text points at the handwritten-entry convention — which would then trigger AB4800 (both an entry and route modules).

Observed on framework main af1c185 (agent-bundle@0.0.0-preview-af1c185).

Minimal repro

repro/
  package.json                 { "name": "repro", "private": true, "type": "module", "version": "0.0.1" }
  agent-bundle.config.ts
  src/mcp/demo/tools/status.tsx

agent-bundle.config.ts:

import { defineConfig } from 'agent-bundle/config';

export default defineConfig({
  mcp: {
    servers: {
      // route-generated server (src/mcp/demo/tools/*.tsx) that only wants extra env
      demo: { env: { DEMO_MODE: 'strict' } },
    },
  },
  plugin: { description: 'AB4304 repro', name: 'repro', version: '0.0.1' },
  targets: ['portable'],
});

src/mcp/demo/tools/status.tsx:

import { Agent } from '@agent-bundle/runtime';
import type { ToolConfig, ToolRouteProps } from 'agent-bundle';
import React from 'react';
import { z } from 'zod';

export const config = { annotations: { readOnlyHint: true }, description: 'Read status.' } satisfies ToolConfig;
export const inputSchema = z.object({}).strict();
export const resultSchema = z.object({ status: z.literal('ready') }).strict();

export default async function Status(_props: ToolRouteProps<typeof inputSchema>) {
  return <Agent.Result value={{ status: 'ready' }}><Agent.Text>ready</Agent.Text></Agent.Result>;
}
$ agent-bundle validate --json
[{"code":"AB4304","message":"MCP server \"demo\" must define exactly one of entry, command, or url, or provide the conventional stdio entry src/mcp/demo.ts.", ...}]

Delete the mcp block → Validation succeeded (and the server builds). Replace env with apps: { panel: { entry: './views/panel.ts', resourceUri: 'ui://repro/panel.html' } }AB4304 + AB4322.

Expected

Either

  1. validateMcpServer/validateMcpApps accept a declaration for a server that the route graph compiles in generated mode when it carries only the keys normalization honors (env, args, targets, apps), and reject entry/command/url there via the existing AB4800; or
  2. the restriction is deliberate, in which case AB4304's message/recovery should say so for generated servers, and docs/framework-mode.md should document that generated servers take no config declaration (env/args/targets/apps only through routes).

Context

Hit while re-porting ScriptedAlchemy/movie-library onto af1c185: the widget MCP App was declared under mcp.servers['movie-library-library'].apps and had to move to the src/mcp/movie-library-library/apps/widget.ts route convention (which works fine).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingmeta-frameworkAgent Bundle compiler-coupled meta-framework

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions