fix(web): address PR review (clean .md output, one MCP config source)

- .md output rewrites MDX-only syntax (Tabs, TabItem, asides, the MCP
  client component) into plain Markdown.
- MCP client setups live in one data file used by the landing page, the
  setup page and agents/install; the smoke-test claim names the five
  agents agent-smoke.sh actually drives (not Cursor).
- The landing page reads the version from Cargo.toml; the hand-copied BBCA
  data stays dated, and the design doc no longer promises capture.sh.
- MCP overview counts 11 tools plus the opt-in ownership_sync.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
hermes 2026-10-15 05:29:02 +00:00
commit 3623c50953
8 changed files with 101 additions and 121 deletions

View file

@ -0,0 +1,15 @@
---
import { Code, TabItem, Tabs } from '@astrojs/starlight/components';
import { mcpClients } from '../data/mcp-clients';
---
<Tabs syncKey="agent">
{
mcpClients.map((c) => (
<TabItem label={c.label}>
<p>{/[~/]/.test(c.file) ? <code>{c.file}</code> : c.file}</p>
<Code code={c.code} lang={c.lang} />
</TabItem>
))
}
</Tabs>

View file

@ -3,6 +3,8 @@ title: Agent-led install
description: Instructions for a coding agent to install idx and register idx-mcp with itself.
---
import McpClientTabs from '../../../components/McpClientTabs.astro';
This page is written for a coding agent. A user sent you here to install
**idx** (a CLI for Indonesian stock market and KSEI ownership data) and
register its MCP server, **idx-mcp**, with the agent harness you are running
@ -44,22 +46,14 @@ Confirm with `idx version` (or `npx -y idx-cli version`).
## 3. Register idx-mcp with yourself
Work out which harness you are, then apply its setup. Use `npx` and
`["-y", "idx-mcp"]` as command and arguments, or `idx-mcp` with no arguments
if you installed the binary.
Work out which harness you are, then apply its setup below. If you installed
the `idx-mcp` binary instead of using Node.js, use the command `idx-mcp` with
no arguments in place of `npx -y idx-mcp`. For any other harness, find how it
registers a stdio MCP server, and ask the user if unsure.
| Harness | How |
| --- | --- |
| Claude Code | run `claude mcp add idx -- npx -y idx-mcp` |
| Codex | add to `~/.codex/config.toml`: `[mcp_servers.idx]` with `command = "npx"`, `args = ["-y", "idx-mcp"]` |
| Cursor | add to `~/.cursor/mcp.json` under `mcpServers`: `"idx": {"command": "npx", "args": ["-y", "idx-mcp"]}` |
| opencode | add to `~/.config/opencode/opencode.json` under `mcp`: `"idx": {"type": "local", "command": ["npx", "-y", "idx-mcp"], "enabled": true}` |
| pi | add to `~/.pi/agent/mcp.json` under `mcpServers`: `"idx": {"command": "npx", "args": ["-y", "idx-mcp"], "exposure": "direct"}` |
| Hermes | add to `~/.hermes/config.yaml` under `mcp_servers`: `idx` with `command: npx`, `args: ["-y", "idx-mcp"]`, `enabled: true` |
| anything else | find how your harness registers a stdio MCP server, and ask the user if unsure |
<McpClientTabs />
Merge into existing files; never overwrite other servers or settings. Full
examples: [MCP setup](/mcp/setup/).
Merge into existing files; never overwrite other servers or settings.
## 4. Download ownership data

View file

@ -5,7 +5,7 @@ description: idx-mcp serves idx's stock and ownership data to AI agents over MCP
`idx-mcp` is a [Model Context Protocol](https://modelcontextprotocol.io)
server over stdio. It gives an agent the same data as the `idx` CLI, as
[11 tools](/mcp/tools/): quotes, price history, screening, company data,
[11 tools](/mcp/tools/) (plus an opt-in `ownership_sync`): quotes, price history, screening, company data,
analysis, comparison, and the KSEI ownership queries.
It shares idx's [config, cache and ownership database](/start/config/#files-idx-keeps),

View file

@ -5,7 +5,7 @@ sidebar:
label: Setup
---
import { Tabs, TabItem } from '@astrojs/starlight/components';
import McpClientTabs from '../../../components/McpClientTabs.astro';
:::tip[Quickest: let your agent do it]
Paste this into your coding agent. It follows
@ -33,91 +33,10 @@ nix profile install github:0xrsydn/idx-cli#idx-mcp
## 2. Add it to your client
<Tabs syncKey="agent">
<TabItem label="Claude Code">
<McpClientTabs />
```bash
claude mcp add idx -- npx -y idx-mcp
```
</TabItem>
<TabItem label="Codex">
`~/.codex/config.toml`:
```toml
[mcp_servers.idx]
command = "npx"
args = ["-y", "idx-mcp"]
```
</TabItem>
<TabItem label="Cursor">
`~/.cursor/mcp.json` (or `.cursor/mcp.json` in a project):
```json
{
"mcpServers": {
"idx": { "command": "npx", "args": ["-y", "idx-mcp"] }
}
}
```
</TabItem>
<TabItem label="opencode">
`opencode.json` in a project, or `~/.config/opencode/opencode.json`:
```json
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"idx": { "type": "local", "command": ["npx", "-y", "idx-mcp"], "enabled": true }
}
}
```
</TabItem>
<TabItem label="pi">
`~/.pi/agent/mcp.json`:
```json
{
"mcpServers": {
"idx": { "command": "npx", "args": ["-y", "idx-mcp"], "exposure": "direct" }
}
}
```
`"exposure": "direct"` gives the agent each tool by name.
</TabItem>
<TabItem label="Hermes">
`~/.hermes/config.yaml`:
```yaml
mcp_servers:
idx:
command: npx
args: ["-y", "idx-mcp"]
enabled: true
```
</TabItem>
<TabItem label="Other">
Any MCP client that runs stdio servers: command `npx`, arguments
`-y idx-mcp` (or the command `idx-mcp` if installed). Add `--allow-sync` to
the arguments to expose `ownership_sync`.
</TabItem>
</Tabs>
These are the setups that `tests/agents/agent-smoke.sh` drives with real
agents.
The Claude Code, Codex, opencode, pi and Hermes setups are the ones
`tests/agents/agent-smoke.sh` drives with the real agents.
## 3. Get ownership data

View file

@ -0,0 +1,32 @@
// The one list of MCP client setups, used by the landing page, the MCP setup
// page and agents/install.md (and their .md output).
export interface McpClient {
id: string;
label: string;
/** Where the config goes, shown above the snippet. */
file: string;
lang: string;
code: string;
/** Driven by tests/agents/agent-smoke.sh against the real agent. */
smokeTested: boolean;
}
export const mcpClients: McpClient[] = [
{ id: 'claude', label: 'Claude Code', file: 'Run in a terminal', lang: 'bash', smokeTested: true, code: 'claude mcp add idx -- npx -y idx-mcp' },
{ id: 'codex', label: 'Codex', file: '~/.codex/config.toml', lang: 'toml', smokeTested: true, code: '[mcp_servers.idx]\ncommand = "npx"\nargs = ["-y", "idx-mcp"]' },
{ id: 'cursor', label: 'Cursor', file: '~/.cursor/mcp.json (or .cursor/mcp.json in a project)', lang: 'json', smokeTested: false, code: '{\n "mcpServers": {\n "idx": { "command": "npx", "args": ["-y", "idx-mcp"] }\n }\n}' },
{ id: 'opencode', label: 'opencode', file: '~/.config/opencode/opencode.json (or opencode.json in a project)', lang: 'json', smokeTested: true, code: '{\n "$schema": "https://opencode.ai/config.json",\n "mcp": {\n "idx": { "type": "local", "command": ["npx", "-y", "idx-mcp"], "enabled": true }\n }\n}' },
{ id: 'pi', label: 'pi', file: '~/.pi/agent/mcp.json', lang: 'json', smokeTested: true, code: '{\n "mcpServers": {\n "idx": { "command": "npx", "args": ["-y", "idx-mcp"], "exposure": "direct" }\n }\n}' },
{ id: 'hermes', label: 'Hermes', file: '~/.hermes/config.yaml', lang: 'yaml', smokeTested: true, code: 'mcp_servers:\n idx:\n command: npx\n args: ["-y", "idx-mcp"]\n enabled: true' },
{ id: 'other', label: 'Other', file: 'Any MCP client that runs stdio servers', lang: 'text', smokeTested: false, code: 'command: npx\nargs: -y idx-mcp\n# or the command idx-mcp, if installed\n# add --allow-sync to expose ownership_sync' },
];
export const smokeTestedLabels = mcpClients.filter((c) => c.smokeTested).map((c) => c.label);
/** The setups as Markdown, for the .md output of pages that render <McpClientTabs />. */
export function mcpClientsMarkdown(): string {
return mcpClients
.map((c) => `### ${c.label}\n\n${c.file}:\n\n\`\`\`${c.lang}\n${c.code}\n\`\`\``)
.join('\n\n');
}

View file

@ -1,15 +1,37 @@
// Serves every docs page as raw Markdown at `<path>.md`, so agents can read
// the docs without HTML (for example /agents/install.md).
// Serves every docs page as plain Markdown at `<path>.md`, so agents can read
// the docs without HTML (for example /agents/install.md). MDX-only syntax is
// rewritten into Markdown.
import type { APIRoute, GetStaticPaths } from 'astro';
import { getCollection } from 'astro:content';
import { mcpClientsMarkdown } from '../data/mcp-clients';
export const getStaticPaths: GetStaticPaths = async () => {
const docs = await getCollection('docs');
return docs.map((entry) => ({ params: { slug: entry.id }, props: { entry } }));
};
function toPlainMarkdown(title: string, body: string): string {
const text = body
.replace(/<!--[\s\S]*?-->\n*/g, '')
.replace(/^import .*\n+/gm, '')
.replace(/^<McpClientTabs \/>$/gm, () => mcpClientsMarkdown())
// <Tabs>: each <TabItem label="X"> becomes a bold label.
.replace(/^<\/?Tabs[^>]*>\n*/gm, '')
.replace(/^<TabItem label="([^"]+)">$/gm, '**$1**')
.replace(/^<\/TabItem>\n*/gm, '')
// Asides (:::tip[Title] ... :::) become blockquote-free sections.
.replace(/^:::\w+\[([^\]]+)\]$/gm, '**$1**\n')
.replace(/^:::\w+$/gm, '')
.replace(/^:::$/gm, '')
.replace(/^```(\w+) wrap$/gm, '```$1')
.replace(/\n{3,}/g, '\n\n')
.trim();
return `# ${title}\n\n${text}\n`;
}
export const GET: APIRoute = ({ props }) => {
const { entry } = props;
const body = `# ${entry.data.title}\n\n${entry.body ?? ''}`.replace(/<!--[\s\S]*?-->\n*/g, '').replace(/^import .*\n+/gm, '');
return new Response(body, { headers: { 'Content-Type': 'text/markdown; charset=utf-8' } });
return new Response(toPlainMarkdown(entry.data.title, entry.body ?? ''), {
headers: { 'Content-Type': 'text/markdown; charset=utf-8' },
});
};

View file

@ -4,6 +4,11 @@ import '@fontsource/ibm-plex-sans/600.css';
import '@fontsource/ibm-plex-sans/700.css';
import '@fontsource/jetbrains-mono/400.css';
import '@fontsource/jetbrains-mono/700.css';
import { readFileSync } from 'node:fs';
import { mcpClients, smokeTestedLabels } from '../data/mcp-clients';
// The released version, from the workspace Cargo.toml (builds run in web/).
const version = readFileSync('../Cargo.toml', 'utf8').match(/^version = "([^"]+)"/m)?.[1] ?? '';
const agentPrompt =
'Install idx-cli and its MCP server for me by following https://idx.rasyidanaf.com/agents/install.md, then show me that it works.';
@ -16,17 +21,10 @@ const installs = [
{ id: 'agent', label: 'Ask your agent', cmd: agentPrompt, prompt: true, note: 'Paste into Claude Code, Codex, Cursor or any coding agent. It installs idx, registers idx-mcp with itself, and asks before changing global config.' },
];
const agents = [
{ id: 'claude', label: 'Claude Code', file: 'terminal', code: 'claude mcp add idx -- npx -y idx-mcp' },
{ id: 'codex', label: 'Codex', file: '~/.codex/config.toml', code: '[mcp_servers.idx]\ncommand = "npx"\nargs = ["-y", "idx-mcp"]' },
{ id: 'cursor', label: 'Cursor', file: '~/.cursor/mcp.json', code: '{\n "mcpServers": {\n "idx": { "command": "npx", "args": ["-y", "idx-mcp"] }\n }\n}' },
{ id: 'opencode', label: 'opencode', file: 'opencode.json', code: '{\n "mcp": {\n "idx": { "type": "local", "command": ["npx", "-y", "idx-mcp"] }\n }\n}' },
{ id: 'pi', label: 'pi', file: '~/.pi/agent/mcp.json', code: '{\n "mcpServers": {\n "idx": { "command": "npx", "args": ["-y", "idx-mcp"], "exposure": "direct" }\n }\n}' },
{ id: 'hermes', label: 'Hermes', file: '~/.hermes/config.yaml', code: 'mcp_servers:\n idx:\n command: npx\n args: ["-y", "idx-mcp"]\n enabled: true' },
{ id: 'other', label: 'Other', file: 'any MCP client (stdio)', code: 'command: npx\nargs: -y idx-mcp\n# add --allow-sync to expose ownership_sync' },
];
const agents = mcpClients;
// Captured from `idx ownership ticker BBCA` on the 2026-09-30 snapshot.
// Captured by hand from `idx ownership ticker BBCA` on the 2026-09-30 snapshot;
// the section shows that date. Refresh it (and the terminal panel) after a new month.
const holders = [
{ name: 'DWIMURIA INVESTAMA ANDALAN', type: 'Corporate', shares: '67,729,950,000', pct: 54.94 },
{ name: 'ANTHONI SALIM', type: 'Individual', shares: '1,416,306,835', pct: 1.15 },
@ -69,7 +67,7 @@ const copyIcon =
<main>
<section class="wrap hero">
<div class="hero-text">
<div class="eyebrow">v0.3.1 · Rust · MIT</div>
<div class="eyebrow">v{version} · Rust · MIT</div>
<h1>Indonesian stocks and ownership, in your terminal and your agent.</h1>
<p class="lede">Quotes, fundamentals, technicals and KSEI shareholder data for every IDX stock. Tables for you, JSON for scripts, and an MCP server for AI agents.</p>
@ -143,7 +141,7 @@ TLKM.JK 2,250 <span class="up">+0.45%</span> 87,159,900
<section id="agents" class="wrap split">
<div class="side">
<h2 class="h2">Add idx to your agent</h2>
<p class="muted-p">idx-mcp serves the same data over stdio. Each setup below is the one our agent smoke test runs against real agents.</p>
<p class="muted-p">idx-mcp serves the same data over stdio. Our agent smoke test runs the {new Intl.ListFormat("en", { type: "conjunction" }).format(smokeTestedLabels)} setups against the real agents.</p>
<div class="card">
<div class="label">Ask it</div>
<div class="ask">"Who are BBCA's largest holders, and what changed last month?"</div>
@ -156,7 +154,7 @@ TLKM.JK 2,250 <span class="up">+0.45%</span> 87,159,900
<button type="button" class="copy" data-copy={agentPrompt} aria-label="Copy agent prompt" set:html={copyIcon} />
</div>
</div>
<a class="more" href="/mcp/tools/">See all 11 tools →</a>
<a class="more" href="/mcp/tools/">See all tools →</a>
</div>
<div class="main-col tabs" data-tabs>