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.tsxAbout
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.
{
"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
3linear`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.
filesA filesystem server with no arguments is usually rooted at `/`.
<McpConfigEditor
servers={servers}
inspect={true}
onChange={setText}
/>Examples
Four servers, three problems
<McpConfigEditor servers={servers} />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'>.
| Prop | Type | Default | Description |
|---|---|---|---|
| servers | Record<string, McpServerConfig> | required | The mcpServers object. Rendered as JSON, inspected as a shape. |
| onChange | (text: string) => void | — | Editable when given. Receives the raw text; parse failures are surfaced. |
| findings | ConfigFinding[] | [] | Extra findings from your own validation, merged with the built-in ones. |
| inspect | boolean | true | Turn off the built-in shape checks. |
| filePath | string | 'mcp.json' | — |
| okLabel | string | 'No problems found in the shape of this config.' | — |
| label | string | 'Findings' | — |
Functions
| Function | Signature | Description |
|---|---|---|
| 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.
| Field | Type | Description |
|---|---|---|
| server | string | — |
| level | 'error' | 'warning' | — |
| message | ReactNode | — |
McpServerConfig
| Field | Type | Description |
|---|---|---|
| command? | string | — |
| args? | string[] | — |
| url? | string | — |
| env? | Record<string, string> | — |
Behaviour
| Topic | Detail | Description |
|---|---|---|
| checks | four, each earned | No 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 only | never blocks | A config being edited is invalid most of the time. A component that refuses to render until it is valid is useless while typing. |