MCP Config Editor

The mcpServers config with the mistakes people actually make called out. The usual failure parses cleanly and the server silently never appears — the error is in the shape, not the syntax, so a JSON editor catches none of it.

src/components/ui/mcp-config-editor.tsx

About

From the component's own source, where it was written.

The mcpServers config, with the mistakes people actually make called out.

Every MCP client is configured by hand-editing JSON, and the failure mode is always the same: it parses, the client starts, and a server silently never appears. The error is in the shape, not the syntax — so a plain JSON editor with syntax highlighting catches none of it.

The checks are the ones worth having, each earned from a real way this goes wrong:

- **command missing** on a stdio server, or url missing on a remote one. - **A bare command** like server-filesystem with no runner — works in your shell because of PATH, fails under a client that spawns without one. - **A secret pasted inline.** An API key in a config file gets committed. - **No arguments on a filesystem-style server**, which usually means it is rooted at /.

Findings are advisory and never block editing: a config can be mid-edit and a component that refuses to render until it is valid is useless while typing.

Install

npx astralyx-ui add mcp-config-editor

Usage

import { McpConfigEditor } from '@/components/ui/mcp-config-editor'

<McpConfigEditor servers={servers} onChange={setText} />

Composer

Change the props and the source below follows.

mcp.json
json
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/Users/ada/work"
      ]
    },
    "linear": {
      "url": "https://mcp.linear.app/sse",
      "env": {
        "LINEAR_API_KEY": "lin_api_8f2a91c4e7"
      }
    },
    "postgres": {
      "command": "server-postgres",
      "args": [
        "--dsn",
        "postgres://localhost/app"
      ]
    },
    "files": {
      "command": "npx",
      "args": []
    }
  }
}

Findings

3
  • linear

    `LINEAR_API_KEY` looks like a secret pasted inline. Reference an environment variable instead.

  • postgres

    `server-postgres` is a bare command. It resolves from your shell’s PATH, which a client that spawns without one will not have.

  • files

    A filesystem server with no arguments is usually rooted at `/`.

Props
tsx
<McpConfigEditor
  servers={servers}
  inspect={true}
  onChange={setText}
/>

Examples

Four servers, three problems

API

Generated from the source, so it cannot fall behind the code. One table per exported component, then hooks, functions and types.

McpConfigEditor

Extends Omit<ComponentProps<'div'>, 'onChange'>.

PropTypeDefaultDescription
serversRecord<string, McpServerConfig>requiredThe mcpServers object. Rendered as JSON, inspected as a shape.
onChange(text: string) => void—Editable when given. Receives the raw text; parse failures are surfaced.
findingsConfigFinding[][]Extra findings from your own validation, merged with the built-in ones.
inspectbooleantrueTurn off the built-in shape checks.
filePathstring'mcp.json'—
okLabelstring'No problems found in the shape of this config.'—
labelstring'Findings'—

Functions

FunctionSignatureDescription
inspectMcpConfig(servers: Record<string, McpServerConfig>) => ConfigFinding[]Exported, so a save handler can run the same checks before writing the file.

Types

ConfigFinding

The mcpServers config, with the mistakes people actually make called out.

FieldTypeDescription
serverstring—
level'error' | 'warning'—
messageReactNode—

McpServerConfig

FieldTypeDescription
command?string—
args?string[]—
url?string—
env?Record<string, string>—

Behaviour

TopicDetailDescription
checksfour, each earnedNo command or url; a bare command that only resolves from your shell’s PATH; a secret pasted inline; a filesystem server with no arguments, which usually means rooted at /.
advisory onlynever blocksA config being edited is invalid most of the time. A component that refuses to render until it is valid is useless while typing.