Skip to content

Commit 8f0aab1

Browse files
oceans404claude
andcommitted
Add "For agents" panel for Raven MCP and Stellar Skills (#2586)
Adds a floating "For agents" button to the bottom right of every docs page. It opens a docked panel with the ways to point an AI agent at Stellar: the Raven MCP server, Stellar Skills, and llms.txt. Placement follows the design pass in Figma ("Agent menu"), which replaced the original plan of a navbar dropdown next to search, so config/theme/navbar.ts is untouched. All copy and commands live in src/data/agentTools.ts, which both the panel and the Building with AI page render. The page's per-client Tabs are now generated from that data instead of hand-written, so the two cannot drift apart. Both use the `mcp-client` tab group, so a tool picked in the panel is already selected on the page and vice versa. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent e8416b6 commit 8f0aab1

9 files changed

Lines changed: 1063 additions & 87 deletions

File tree

docs/build/building-with-ai.mdx

Lines changed: 8 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ sidebar_label: Building with AI
55
sidebar_position: 1
66
---
77

8-
import Tabs from "@theme/Tabs";
9-
import TabItem from "@theme/TabItem";
8+
import {
9+
RavenConnectTabs,
10+
SkillsInstallTabs,
11+
} from "@site/src/components/AgentSetup";
1012

1113
# Building with AI
1214

@@ -35,75 +37,9 @@ Unlike the static [`llms.txt`](#using-llmstxt) file and the installable [Stellar
3537

3638
Add the server, then sign in. Sign-in happens inside your own client (Raven uses OAuth), so the first request opens your browser to authorize. For full setup details see [raven.stellar.buzz](https://raven.stellar.buzz).
3739

38-
<Tabs groupId="mcp-client" defaultValue="claude-code">
39-
<TabItem value="claude-code" label="Claude Code">
40+
{/* Rendered from src/data/agentTools.ts, shared with the "For agents" panel. */}
4041

41-
```bash
42-
claude mcp add --transport http stellar-raven "https://raven.stellar.buzz/mcp"
43-
# then run /mcp -> Authenticate -> sign in in your browser
44-
```
45-
46-
</TabItem>
47-
<TabItem value="codex" label="Codex">
48-
49-
```bash
50-
codex mcp add stellar-raven --url "https://raven.stellar.buzz/mcp"
51-
codex mcp login stellar-raven # opens your browser
52-
```
53-
54-
</TabItem>
55-
<TabItem value="cursor" label="Cursor">
56-
57-
Add to `~/.cursor/mcp.json` (or `.cursor/mcp.json` per project). Cursor runs the OAuth sign-in on first use.
58-
59-
```json
60-
{
61-
"mcpServers": {
62-
"stellar-raven": { "url": "https://raven.stellar.buzz/mcp" }
63-
}
64-
}
65-
```
66-
67-
</TabItem>
68-
<TabItem value="claude-desktop" label="Claude Desktop">
69-
70-
Go to **Settings → Connectors → Add custom connector**, paste the endpoint, and approve the browser sign-in.
71-
72-
```text
73-
https://raven.stellar.buzz/mcp
74-
```
75-
76-
</TabItem>
77-
<TabItem value="vscode" label="VS Code">
78-
79-
```bash
80-
code --add-mcp '{"name":"stellar-raven","type":"http","url":"https://raven.stellar.buzz/mcp"}'
81-
```
82-
83-
</TabItem>
84-
<TabItem value="other" label="Other clients">
85-
86-
For clients without native remote/OAuth support, bridge with [`mcp-remote`](https://github.com/geelen/mcp-remote):
87-
88-
```json
89-
{
90-
"mcpServers": {
91-
"stellar-raven": {
92-
"command": "npx",
93-
"args": [
94-
"-y",
95-
"mcp-remote@latest",
96-
"https://raven.stellar.buzz/mcp",
97-
"--transport",
98-
"http-only"
99-
]
100-
}
101-
}
102-
}
103-
```
104-
105-
</TabItem>
106-
</Tabs>
42+
<RavenConnectTabs />
10743

10844
## Stellar Skills
10945

@@ -147,24 +83,9 @@ Skills can be installed on any AI coding tool that supports the [Agent Skills](h
14783
| [OpenCode](https://opencode.ai) | `~/.config/opencode/skills/` |
14884
| [OpenAI Codex](https://openai.com/index/openai-codex) | `~/.codex/skills/` |
14985

150-
#### Claude Code
151-
152-
```bash
153-
/plugin marketplace add stellar/stellar-dev-skill
154-
/plugin install stellar-dev@stellar-dev
155-
```
86+
{/* Rendered from src/data/agentTools.ts, shared with the "For agents" panel. */}
15687

157-
#### OpenAI Codex
158-
159-
```bash
160-
git clone https://github.com/stellar/stellar-dev-skill ~/.codex/skills/stellar-dev-skill
161-
```
162-
163-
#### Using npx (works with any compatible tool)
164-
165-
```bash
166-
npx skills add https://github.com/stellar/stellar-dev-skill
167-
```
88+
<SkillsInstallTabs />
16889

16990
#### Manual installation
17091

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import React, { type ReactNode } from 'react';
2+
import Tabs from '@theme/Tabs';
3+
import TabItem from '@theme/TabItem';
4+
import CodeBlock from '@theme/CodeBlock';
5+
import Link from '@docusaurus/Link';
6+
7+
import {
8+
AGENT_TOOL_GROUP_ID,
9+
AGENT_TOOLS,
10+
DEFAULT_AGENT_TOOL_ID,
11+
type ToolInstructions,
12+
} from '@site/src/data/agentTools';
13+
14+
/**
15+
* The Building with AI page's rendering of the shared agent setup content in
16+
* `src/data/agentTools`. The "For agents" panel renders the same data, so the
17+
* page and the panel cannot fall out of sync.
18+
*
19+
* Both use the `mcp-client` tab group, which means a tool picked in the panel
20+
* is already selected when the reader lands here.
21+
*/
22+
23+
function Instructions({ instructions }: { instructions: ToolInstructions }): ReactNode {
24+
return (
25+
<>
26+
{instructions.note && <p>{instructions.note}</p>}
27+
{instructions.snippets.map((snippet) => (
28+
<CodeBlock key={snippet.code} language={snippet.language}>
29+
{snippet.code}
30+
</CodeBlock>
31+
))}
32+
{instructions.links && (
33+
<p>
34+
{instructions.links.map((link, index) => (
35+
<React.Fragment key={link.href}>
36+
{index > 0 && ' · '}
37+
<Link to={link.href}>{link.label}</Link>
38+
</React.Fragment>
39+
))}
40+
</p>
41+
)}
42+
</>
43+
);
44+
}
45+
46+
function AgentToolTabs({
47+
render,
48+
}: {
49+
render: (tool: (typeof AGENT_TOOLS)[number]) => ReactNode;
50+
}): ReactNode {
51+
return (
52+
<Tabs groupId={AGENT_TOOL_GROUP_ID} defaultValue={DEFAULT_AGENT_TOOL_ID}>
53+
{AGENT_TOOLS.map((tool) => (
54+
<TabItem key={tool.id} value={tool.id} label={tool.label}>
55+
{render(tool)}
56+
</TabItem>
57+
))}
58+
</Tabs>
59+
);
60+
}
61+
62+
/** Per-client instructions for connecting an agent to the Raven MCP server. */
63+
export function RavenConnectTabs(): ReactNode {
64+
return <AgentToolTabs render={(tool) => <Instructions instructions={tool.raven} />} />;
65+
}
66+
67+
/** Per-client instructions for installing the Stellar Skills. */
68+
export function SkillsInstallTabs(): ReactNode {
69+
return (
70+
<AgentToolTabs render={(tool) => <Instructions instructions={tool.skills.install} />} />
71+
);
72+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import React, { useEffect, useRef, useState, type ReactNode } from 'react';
2+
import { translate } from '@docusaurus/Translate';
3+
4+
import styles from './styles.module.scss';
5+
6+
interface Props {
7+
code: string;
8+
}
9+
10+
/**
11+
* A copyable command line. Deliberately not `@theme/CodeBlock`: inside a 400px
12+
* panel we want tight padding, wrapping instead of horizontal scroll, and no
13+
* syntax highlighting bundle.
14+
*/
15+
export default function CopyBlock({ code }: Props): ReactNode {
16+
const [copied, setCopied] = useState(false);
17+
const timeout = useRef<ReturnType<typeof setTimeout>>(undefined);
18+
19+
useEffect(() => () => clearTimeout(timeout.current), []);
20+
21+
const copy = async () => {
22+
try {
23+
await navigator.clipboard.writeText(code);
24+
} catch {
25+
// Clipboard is unavailable (insecure origin, or permission denied).
26+
return;
27+
}
28+
setCopied(true);
29+
clearTimeout(timeout.current);
30+
timeout.current = setTimeout(() => setCopied(false), 2000);
31+
};
32+
33+
return (
34+
<div className={styles.copyBlock}>
35+
<pre className={styles.code}>{code}</pre>
36+
<button
37+
type="button"
38+
className={styles.copyButton}
39+
onClick={copy}
40+
aria-label={
41+
copied
42+
? translate({
43+
message: 'Copied',
44+
id: 'components.ForAgentsPanel.Copied',
45+
description: 'Confirmation shown after copying a command',
46+
})
47+
: translate({
48+
message: 'Copy command',
49+
id: 'components.ForAgentsPanel.Copy',
50+
description: 'Label for the button that copies a command',
51+
})
52+
}>
53+
{copied ? <CheckIcon /> : <ClipboardIcon />}
54+
</button>
55+
</div>
56+
);
57+
}
58+
59+
function ClipboardIcon(): ReactNode {
60+
return (
61+
<svg width="14" height="14" viewBox="0 0 16 16" fill="none" aria-hidden="true">
62+
<rect
63+
x="5.5"
64+
y="5.5"
65+
width="8"
66+
height="9"
67+
rx="1.5"
68+
stroke="currentColor"
69+
strokeWidth="1.3"
70+
/>
71+
<path
72+
d="M10.5 3.5v-.5a1.5 1.5 0 0 0-1.5-1.5H4A1.5 1.5 0 0 0 2.5 3v6A1.5 1.5 0 0 0 4 10.5h.5"
73+
stroke="currentColor"
74+
strokeWidth="1.3"
75+
strokeLinecap="round"
76+
/>
77+
</svg>
78+
);
79+
}
80+
81+
function CheckIcon(): ReactNode {
82+
return (
83+
<svg width="14" height="14" viewBox="0 0 16 16" fill="none" aria-hidden="true">
84+
<path
85+
d="M3 8.5 6.2 11.7 13 4.9"
86+
stroke="currentColor"
87+
strokeWidth="1.6"
88+
strokeLinecap="round"
89+
strokeLinejoin="round"
90+
/>
91+
</svg>
92+
);
93+
}

0 commit comments

Comments
 (0)