File tree Expand file tree Collapse file tree 9 files changed +203
-4
lines changed
routes/[organization]/[project]/-/ai
src/components/code-block Expand file tree Collapse file tree 9 files changed +203
-4
lines changed Original file line number Diff line number Diff line change @@ -8,6 +8,8 @@ import Axios from "axios";
88export const CANONICAL_ADMIN_URL =
99 import . meta. env . RILL_UI_PUBLIC_RILL_ADMIN_URL || "http://localhost:8080" ;
1010
11+ export const CANONICAL_ADMIN_API_URL = `${ CANONICAL_ADMIN_URL . replace ( "https://admin" , "https://api" ) } ` ;
12+
1113/**
1214 * The URL of the admin server.
1315 *
Original file line number Diff line number Diff line change 1+ <script lang =" ts" >
2+ import { CANONICAL_ADMIN_API_URL } from " @rilldata/web-admin/client/http-client" ;
3+ import CodeBlock from " @rilldata/web-common/components/code-block/CodeBlock.svelte" ;
4+
5+ export let organization: string ;
6+ export let project: string ;
7+ export let isPublic: boolean ;
8+ export let issuedToken: string | null = null ;
9+
10+ // Construct the API URL for the MCP server
11+ $ : apiUrl = ` ${CANONICAL_ADMIN_API_URL }/v1/organizations/${organization }/projects/${project }/runtime/mcp/sse ` ;
12+
13+ // Config snippets with exact formatting
14+ $ : publicConfig = ` {
15+ "mcpServers": {
16+ "rill": {
17+ "command": "npx",
18+ "args": [
19+ "mcp-remote",
20+ "${apiUrl }"
21+ ]
22+ }
23+ }
24+ } ` ;
25+
26+ $ : privateConfig = ` {
27+ "mcpServers": {
28+ "rill": {
29+ "command": "npx",
30+ "args": [
31+ "mcp-remote",
32+ "${apiUrl }",
33+ "--header",
34+ "Authorization:\$ {AUTH_HEADER}"
35+ ],
36+ "env": {
37+ "AUTH_HEADER": "Bearer ${issuedToken ? issuedToken : " <Rill personal access token>" }"
38+ }
39+ }
40+ } ` ;
41+ </script >
42+
43+ <div class =" mb-2" >
44+ <h2 class =" text-xl font-semibold mb-2" >Configure your MCP client</h2 >
45+ <p class =" mb-4 text-gray-600" >
46+ Use the below snippet to configure your AI client.
47+ </p >
48+ <CodeBlock code ={isPublic ? publicConfig : privateConfig } language =" json" />
49+ </div >
Original file line number Diff line number Diff line change @@ -18,6 +18,7 @@ export function isProjectPage(page: Page): boolean {
1818 page . route . id === "/[organization]/[project]" ||
1919 page . route . id === "/[organization]/[project]/-/reports" ||
2020 page . route . id === "/[organization]/[project]/-/alerts" ||
21+ page . route . id === "/[organization]/[project]/-/ai" ||
2122 page . route . id === "/[organization]/[project]/-/status" ||
2223 page . route . id === "/[organization]/[project]/-/settings" ||
2324 page . route . id === "/[organization]/[project]/-/settings/public-urls" ||
Original file line number Diff line number Diff line change 1+ <script lang =" ts" >
2+ import { createAdminServiceIssueUserAuthToken } from " @rilldata/web-admin/client" ;
3+ import Button from " @rilldata/web-common/components/button/Button.svelte" ;
4+
5+ export let issuedToken: string | null = null ;
6+
7+ let error: string | null = null ;
8+ let issuing = false ;
9+
10+ const issueTokenMutation = createAdminServiceIssueUserAuthToken ();
11+ const manualClientId = " 12345678-0000-0000-0000-000000000005" ; // This comes from admin/database/database.go
12+
13+ async function issueToken() {
14+ issuing = true ;
15+ error = null ;
16+ issuedToken = null ;
17+ try {
18+ const resp = await $issueTokenMutation .mutateAsync ({
19+ userId: " current" ,
20+ data: {
21+ displayName: " MCP Token" ,
22+ clientId: manualClientId ,
23+ ttlMinutes: " 0" ,
24+ },
25+ });
26+ issuedToken = resp .token ;
27+ } catch (e ) {
28+ error = e ?.message || " Failed to issue token. Please try again." ;
29+ } finally {
30+ issuing = false ;
31+ }
32+ }
33+ </script >
34+
35+ <div class =" mb-2" >
36+ <h2 class =" text-xl font-semibold mb-2" >Create a Personal Access Token</h2 >
37+ <p class =" mb-4 text-gray-600" >
38+ Because this project is <span class =" font-medium" >private</span >, you need a
39+ <span class =" font-medium" >personal access token</span > to use in your MCP configuration.
40+ This token authenticates your requests.
41+ </p >
42+ <Button type ="primary" on:click ={issueToken } disabled ={issuing }>
43+ {issuing ? " Issuing..." : " Create token" }
44+ </Button >
45+
46+ {#if issuedToken }
47+ <div class =" mt-4 mb-2 text-green-700 text-sm font-semibold" >
48+ Token created! Your new token is now included in the configuration snippet
49+ below.
50+ </div >
51+ {/if }
52+
53+ {#if error }
54+ <div class ="text-red-600 mt-2" >{error }</div >
55+ {/if }
56+ </div >
Original file line number Diff line number Diff line change 11<script lang =" ts" >
2- import { type V1ProjectPermissions } from " ../../client" ;
3- import Tab from " @rilldata/web-admin/components/nav/Tab.svelte" ;
42 import {
5- width ,
63 position ,
4+ width ,
75 } from " @rilldata/web-admin//components/nav/Tab.svelte" ;
6+ import Tab from " @rilldata/web-admin/components/nav/Tab.svelte" ;
87 import { featureFlags } from " @rilldata/web-common/features/feature-flags" ;
8+ import { type V1ProjectPermissions } from " ../../client" ;
99
1010 export let projectPermissions: V1ProjectPermissions ;
1111 export let organization: string ;
3030 label: " Alerts" ,
3131 hasPermission: $alerts ,
3232 },
33+ {
34+ route: ` /${organization }/${project }/-/ai ` ,
35+ label: " AI" ,
36+ hasPermission: true ,
37+ },
3338 {
3439 route: ` /${organization }/${project }/-/status ` ,
3540 label: " Status" ,
Original file line number Diff line number Diff line change 1+ <script lang =" ts" >
2+ import { page } from " $app/stores" ;
3+ import { createAdminServiceGetProject } from " @rilldata/web-admin/client" ;
4+ import ContentContainer from " @rilldata/web-admin/components/layout/ContentContainer.svelte" ;
5+ import MCPConfigSection from " @rilldata/web-admin/features/ai/MCPConfigSection.svelte" ;
6+ import PersonalAccessTokensSection from " @rilldata/web-admin/features/personal-access-tokens/PersonalAccessTokensSection.svelte" ;
7+
8+ $ : organization = $page .params .organization ;
9+ $ : project = $page .params .project ;
10+
11+ $ : proj = createAdminServiceGetProject (organization , project );
12+ $ : ({
13+ project: { public: isPublic },
14+ } = $proj .data );
15+
16+ let issuedToken: string | null = null ;
17+ </script >
18+
19+ <ContentContainer maxWidth ={1100 }>
20+ <div class =" flex flex-col gap-y-4 size-full" >
21+ <div class =" flex flex-col gap-y-2" >
22+ <h1 class =" text-2xl font-bold mt-4 mb-2" >
23+ Integrate Rill with your AI client
24+ </h1 >
25+ <p class =" mb-2 text-gray-700" >
26+ Ask questions of your Rill project using natural language in any AI
27+ client that supports the Model Context Protocol (MCP). <a
28+ href =" https://docs.rilldata.com/explore/mcp"
29+ target =" _blank"
30+ rel =" noopener" >Learn more about MCP in the Rill docs</a
31+ >
32+ </p >
33+ </div >
34+ {#if ! isPublic }
35+ <PersonalAccessTokensSection bind:issuedToken />
36+ {/if }
37+ <MCPConfigSection {organization } {project } {isPublic } {issuedToken } />
38+ </div >
39+ </ContentContainer >
Original file line number Diff line number Diff line change 8383 "nearley" : " ^2.20.1" ,
8484 "orval" : " ^7.8.0" ,
8585 "posthog-js" : " ^1.188.0" ,
86+ "prismjs" : " ^1.30.0" ,
8687 "regular-table" : " ^0.5.9" ,
8788 "storybook" : " ^7.0.18" ,
8889 "svelte" : " ^4.2.19" ,
Original file line number Diff line number Diff line change 11<script lang =" ts" >
2+ import Prism from " prismjs" ;
3+ import " prismjs/components/prism-json" ;
4+ import " prismjs/themes/prism.css" ;
5+ import { onMount } from " svelte" ;
6+ import Button from " ../button/Button.svelte" ;
7+
28 export let code: string ;
9+ export let language: string = " json" ;
10+ export let showCopyButton: boolean = true ;
11+
12+ let codeElement: HTMLElement ;
13+ let copied = false ;
14+
15+ function copyCode() {
16+ navigator .clipboard .writeText (code );
17+ copied = true ;
18+ setTimeout (() => (copied = false ), 1500 );
19+ }
20+
21+ onMount (() => {
22+ if (codeElement ) {
23+ Prism .highlightElement (codeElement );
24+ }
25+ });
26+
27+ $ : (async () => {
28+ if (codeElement && code !== undefined && language !== undefined ) {
29+ Prism .highlightElement (codeElement );
30+ }
31+ })();
332 </script >
433
5- <pre ><code >{code }</code ></pre >
34+ <div class =" relative" >
35+ {#if showCopyButton }
36+ <Button
37+ type =" secondary"
38+ on:click ={copyCode }
39+ small
40+ class =" absolute top-2 right-2"
41+ >
42+ {#if copied }Copied!{:else }Copy{/if }
43+ </Button >
44+ {/if }
45+ {#key code + language }
46+ <pre ><code bind:this ={codeElement } class ={` language-${language } ` }
47+ >{code }</code
48+ ></pre >
49+ {/ key }
50+ </div >
651
752<style lang =" postcss" >
853 pre {
You can’t perform that action at this time.
0 commit comments