【実験】Supabase MCPを使って簡易的なTodo List Appを一撃で完成させる
概要
Supabase MCPを使ってCursorでReactによるTodo Listアプリを実験的に作成した経緯になります。
対応したこと(自身が行ったこと)
- SupabaseでのAccess Tokenを新規作成
- CursorのMCPに設定
- 「ReactとSupabaseを使って認証付きのTodo List Appを作成して」とAgent Modeにプロンプトを入力し実行(Modelは claude-3.7-sonnet)
- App完成後、これまでの経緯をBlogとして纏めてと依頼(以下の記事になります)
完成したAppの機能
- Todo Listでのadd/delete
- checkで完了タスクの判定
- ログイン・新規作成
- 新規作成時のMagic Linkによるメール送信
簡易的なAppに割とよくある機能ができました。
SupabaseのAccess Tokenを新規作成
Supabseの登録後、こちらに遷移し
Generate new token
を押下しお試しプロジェクト用のtokenを生成します。
CursorのMCPに設定
{
"mcpServers": {
"supabase": {
"command": "npx",
"args": [
"-y",
"@supabase/mcp-server-supabase@latest",
"--access-token",
"sbp_daxxxxxxxxxxxxxxxxxxx" // ここに生成したtokenを設定
]
}
}
}
プロンプトの入力・実行
「ReactとSupabaseを使って認証付きのTodo List Appを作成して」とCursorのAgent Modeに依頼し、途中色々聞かれるので確認してAcceptしていくとAppが無事完成。
記事化の対応
「ここまでの対応についてBlogにして」と依頼し、できたのが以下文章になります。
記事化の生成物
はじめに
今回はSupabase MCPを活用して、認証機能付きのTodo Listアプリを実装した過程を紹介します。Supabaseはバックエンド機能をすぐに使えるようにしてくれるサービスで、特にReactなどのフロントエンドフレームワークと組み合わせると効率的に開発ができます。
Supabaseとは
Supabaseは「オープンソースのFirebase代替」と呼ばれるBaaS(Backend as a Service)です。PostgreSQLデータベース、認証機能、リアルタイム更新、ストレージ、エッジ関数などを提供しています。
特徴としては:
- PostgreSQLベースのため、既存のSQLの知識がそのまま活かせる
- リアルタイム機能があり、データの変更を即座にクライアントに反映できる
- RLS(Row Level Security)によるデータセキュリティ
- 無料枠が比較的寛大
実装ステップ
1. Supabaseプロジェクトの作成
まず、Supabase MCPを使ってプロジェクトを作成します。
// プロジェクト作成
const { id: projectId } = await supabase.createProject({
name: "todo-app",
organization_id: "組織ID",
region: "ap-northeast-1"
});
2. データベース設計
続いて、Todoデータを格納するためのテーブルを作成します。
CREATE TABLE todos (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
title TEXT NOT NULL,
completed BOOLEAN NOT NULL DEFAULT FALSE,
user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- ユーザー自身のデータのみアクセス可能にするRLSポリシー
CREATE POLICY "Todoはユーザー自身のもののみアクセス可能"
ON todos FOR ALL
USING (auth.uid() = user_id);
このRLSポリシーにより、各ユーザーは自分のTodoのみ閲覧・編集できます。
3. Reactアプリの実装
3.1 プロジェクト構成
src/
├── lib/
│ ├── supabase.ts # Supabase接続設定
│ └── AuthContext.tsx # 認証コンテキスト
├── components/
│ ├── Auth.tsx # 認証コンポーネント
│ ├── Profile.tsx # プロフィール表示
│ ├── TodoItem.tsx # Todo項目
│ └── TodoList.tsx # Todoリスト
└── App.tsx # メインアプリ
3.2 Supabase接続設定
// src/lib/supabase.ts
import { createClient } from '@supabase/supabase-js';
const supabaseUrl = process.env.REACT_APP_SUPABASE_URL;
const supabaseKey = process.env.REACT_APP_SUPABASE_ANON_KEY;
if (!supabaseUrl || !supabaseKey) {
throw new Error('Supabase URL or key is not set');
}
export const supabase = createClient(supabaseUrl, supabaseKey);
環境変数を使用することで、APIキーの安全な管理ができます。
3.3 認証コンテキスト
// src/lib/AuthContext.tsx(一部抜粋)
export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [session, setSession] = useState<Session | null>(null);
const [user, setUser] = useState<User | null>(null);
useEffect(() => {
// 現在のセッションを取得
const getSession = async () => {
const { data: { session } } = await supabase.auth.getSession();
setSession(session);
setUser(session?.user || null);
};
getSession();
// 認証の状態変化を監視
const { data: { subscription } } = supabase.auth.onAuthStateChange(
(_event, session) => {
setSession(session);
setUser(session?.user || null);
}
);
return () => subscription.unsubscribe();
}, []);
// ...
};
3.4 認証コンポーネント
// src/components/Auth.tsx(一部抜粋)
const Auth: React.FC = () => {
// ...
const handleAuth = async (e: React.FormEvent) => {
e.preventDefault();
try {
if (isSignUp) {
// サインアップ処理
const { error } = await supabase.auth.signUp({
email,
password,
options: { emailRedirectTo: window.location.origin },
});
// ...
} else {
// ログイン処理
const { error } = await supabase.auth.signInWithPassword({
email,
password,
});
// ...
}
} catch (error) {
// エラー処理
}
};
// ...
};
3.5 Todoリスト管理
// src/components/TodoList.tsx(一部抜粋)
const TodoList: React.FC = () => {
const { user } = useAuth();
const [todos, setTodos] = useState<Todo[]>([]);
// ユーザーのTodoを取得
useEffect(() => {
if (user) {
const fetchTodos = async () => {
const { data, error } = await supabase
.from('todos')
.select('*')
.eq('user_id', user.id)
.order('created_at', { ascending: false });
if (!error && data) {
setTodos(data);
}
};
fetchTodos();
}
}, [user]);
// Todo追加処理
const addTodo = async (title: string) => {
if (!title.trim() || !user) return;
const { data, error } = await supabase
.from('todos')
.insert([{ title, user_id: user.id }])
.select();
if (!error && data) {
setTodos([...data, ...todos]);
}
};
// 以下、更新・削除処理
// ...
};
4. アプリの統合
App.tsxでは、認証状態に応じて表示するコンポーネントを切り替えています:
function App() {
return (
<AuthProvider>
<AppContent />
</AuthProvider>
);
}
const AppContent: React.FC = () => {
const { user, loading } = useAuth();
if (loading) {
return <LoadingIndicator />;
}
return (
<div>
{user ? (
<>
<Profile />
<TodoList />
</>
) : (
<Auth />
)}
</div>
);
};
実装のポイント
1. 環境変数の活用
Supabaseの接続情報は環境変数を使って管理しています。これにより、APIキーがソースコード内に直接記述されることを防ぎます。
REACT_APP_SUPABASE_URL=https://your-project-id.supabase.co
REACT_APP_SUPABASE_ANON_KEY=your-anon-key
2. RLSによるセキュリティ
Row Level Security(RLS)を使って、各ユーザーが自分のデータのみにアクセスできるようにしています。これはSupabaseの強力な機能の一つです。
3. ユーザー体験の向上
- ログイン・登録を同一フォームで切り替え可能に
- エラーメッセージの分かりやすい表示
- ローディング状態の表示
まとめ
Supabase MCPを使うことで、バックエンド機能を持つTodoアプリをシンプルに実装できました。特に:
- データベース管理(PostgreSQL)
- 認証機能(メール・パスワード)
- セキュリティ(RLS)
これらの機能を自前で実装しようとすると時間がかかりますが、Supabaseを利用することで効率よく開発できます。また、実際のプロダクションでは、より堅牢なエラーハンドリングやテスト、UI/UXの改善などを行うとさらに良いでしょう。
Supabaseは継続的に機能が追加されており、今後もさらに便利になることが期待できます。みなさんもぜひ試してみてください!
記事中のコードは簡略化しています。完全なコードはGitHubで公開しております。
まとめ
簡易的ではありますしUI/UXがお粗末かつ処理ロジックについても何も修正していないのでOh...な部分はあるかと思いますが、Supabaseとの連携で認証やTodo Itemの永続性も担保されるAppをプロンプト一撃で作成することができました。
最近、MCPの熱が高まっているので簡易的にさわれるものとして試してみましたがこりゃ便利です。
Discussion