Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions app/(app)/settings/tokens/connection-guides.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
export const SERVICE_TOKEN_ENV_VAR = "ARIN_MCP_TOKEN";
export const SERVICE_TOKEN_PLACEHOLDER = "arin_your_token_here";

function bearerValue(token?: string): string {
return `Bearer ${token?.trim() || SERVICE_TOKEN_PLACEHOLDER}`;
}

export function mcpServerUrl(appUrl: string): string {
return `${appUrl}/api/mcp`;
}

export function claudeWebFields(appUrl: string) {
return {
name: "Arin",
remoteMcpServerUrl: mcpServerUrl(appUrl),
oauthClientId: "Leave blank",
oauthClientSecret: "Leave blank",
};
}

export function claudeWebBlock(appUrl: string): string {
const fields = claudeWebFields(appUrl);
return [
`Name: ${fields.name}`,
`Remote MCP server URL: ${fields.remoteMcpServerUrl}`,
`OAuth Client ID: ${fields.oauthClientId}`,
`OAuth Client Secret: ${fields.oauthClientSecret}`,
].join("\n");
}

export function claudeCodeMacCommand(appUrl: string, token?: string): string {
return [
"claude mcp add --transport http arin \\",
` ${mcpServerUrl(appUrl)} \\`,
` --header "Authorization: ${bearerValue(token)}"`,
].join("\n");
}

export function claudeCodeWindowsCommand(appUrl: string, token?: string): string {
return [
"claude mcp add --transport http arin `",
` ${mcpServerUrl(appUrl)} \``,
` --header 'Authorization: ${bearerValue(token)}'`,
].join("\n");
}

export function codexMacCommand(appUrl: string, token?: string): string {
return [
`export ${SERVICE_TOKEN_ENV_VAR}="${token?.trim() || SERVICE_TOKEN_PLACEHOLDER}"`,
`codex mcp add arin --url ${mcpServerUrl(appUrl)} --bearer-token-env-var ${SERVICE_TOKEN_ENV_VAR}`,
"codex mcp list",
].join("\n");
}

export function codexWindowsCommand(appUrl: string, token?: string): string {
return [
`$env:${SERVICE_TOKEN_ENV_VAR}="${token?.trim() || SERVICE_TOKEN_PLACEHOLDER}"`,
`codex mcp add arin --url ${mcpServerUrl(appUrl)} --bearer-token-env-var ${SERVICE_TOKEN_ENV_VAR}`,
"codex mcp list",
].join("\n");
}

export function genericHttpConfig(appUrl: string, token?: string): string {
return `{
"mcpServers": {
"arin": {
"type": "http",
"url": "${mcpServerUrl(appUrl)}",
"headers": {
"Authorization": "${bearerValue(token)}"
}
}
}
}`;
}
8 changes: 5 additions & 3 deletions app/(app)/settings/tokens/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { desc, eq } from "drizzle-orm";
import { db } from "@/db/client";
import { serviceTokens } from "@/db/schema/settings";
import { env } from "@/lib/env";
import { relativeTime } from "@/lib/format";
import { requireOrgSession } from "@/lib/session";
import { TokensClient } from "./tokens-client";
Expand All @@ -20,7 +21,7 @@ export default async function ServiceTokensSettingsPage() {
.orderBy(desc(serviceTokens.createdAt));

return (
<div className="max-w-[560px] space-y-5">
<div className="max-w-[760px] space-y-5">
<header>
<h2
className="text-base font-semibold tracking-tight text-text"
Expand All @@ -29,12 +30,13 @@ export default async function ServiceTokensSettingsPage() {
Service Tokens (MCP)
</h2>
<p className="mt-1 text-[12px] text-text-muted">
Service tokens authenticate Claude (over MCP) to your workspace. Each token is
shown once at creation — store it in your MCP client config.
Connect Claude, Codex, and other MCP clients to your workspace. Claude Web
uses OAuth; service-token clients show the token only once at creation.
</p>
</header>

<TokensClient
appUrl={env.APP_URL}
tokens={rows.map((r) => ({
id: r.id,
name: r.name,
Expand Down
Loading
Loading