Home
back

Next.js + Vercel AI SDK + Gemini , MCP作成

id: 196, 2025-05-23

### 音声概要

・AIで生成された 音声概要になります。


### 概要

  • Next.js + Vercel AI SDK , MCP Host的なメモになります。
  • LLMは、Gemini

[ 公開 2025/05/08 ]


### 構成

  • Next 15
  • LLM: gemini
  • node20

### 関連


### 書いたコード


  • next.jsに、AI関係ライブラリ追加
npm i ai @ai-sdk/react @ai-sdk/google zod

  • .env
  • gemini API 設定
GOOGLE_GENERATIVE_AI_API_KEY="key"

  • package.json
{
  "name": "mcp-nextjs",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev --turbopack",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "@ai-sdk/google": "^1.2.11",
    "@ai-sdk/react": "^1.2.9",
    "ai": "^4.3.9",
    "next": "15.3.0",
    "react": "^19.0.0",
    "react-dom": "^19.0.0",
    "zod": "^3.24.3"
  },
  "devDependencies": {
    "@tailwindcss/postcss": "^4",
    "@types/node": "^20",
    "@types/react": "^19",
    "@types/react-dom": "^19",
    "tailwindcss": "^4",
    "typescript": "^5"
  }
}

  • tree
$ tree .
.
├── app
│   ├── api
│   │   └── chat
│   │       └── route.ts
│   ├── favicon.ico
│   ├── globals.css
│   ├── layout.tsx
│   ├── lib
│   ├── page.tsx
│   └── tools
│       └── getNumber.ts
├── next-env.d.ts
├── next.config.ts
├── package.json
├── postcss.config.mjs
├── public
└── tsconfig.json

  • api
  • app/api/chat/route.ts
  • generateText 使います。
import { NextResponse } from "next/server";
import { google } from "@ai-sdk/google";
import { streamText, tool } from "ai";
import { generateText } from "ai";
import { z } from "zod";

import { getNumber } from "../../tools/getNumber";

const MODEL_NAME = "gemini-2.0-flash";

export async function POST(req: Request) {
  const { messages } = await req.json();
  //console.log("msg=", messages);
  const result = await generateText({
    model: google(MODEL_NAME),
    tools: {
      getNumber ,
    },
    maxSteps: 5,
    messages: [{ role: "user", content: messages }],
  });
  console.log("artifact:");
  console.log(result.text);
  return NextResponse.json({ret: 200, text: result.text});
}

  • tool: サイコロ実行の例
  • app/tools/getNumber.ts
import { generateText, tool } from "ai";
import { z } from "zod";

// サイコロを振ってください。1から6までの整数を返してください。
export const getNumber = tool({
  description: "入力された面数のサイコロを振ります。",
  parameters: z.object({
    dice: z.number().min(1).describe("サイコロの面数").optional().default(6),
  }),
  execute: async ({ dice }) => {
    return Math.floor(Math.random() * dice) + 1;
  },
});

  • mcp-nextjs/app/page.tsx
"use client";
 
import {useState}  from "react";

export default function Chat() {
  const [text, setText] = useState<string>("");

  const chatStart = async function(){
    try{    
      const elem = document.getElementById("input_text");
      let inText = "";
      if(elem){
        inText = elem.value;
      };
      console.log("inText=", inText);
      if(!inText){ return; }
      const item = {messages: inText};
      const body: any = JSON.stringify(item);		
      const res = await fetch("/api/chat", {
        method: "POST",
        headers: {"Content-Type": "application/json"},      
        body: body
      });
      const json = await res.json();
      console.log(json);
      setText(json.text);
    } catch(e){
      console.error(e);
    }
  }

  return (
    <div className="flex flex-col w-full max-w-2xl py-24 mx-auto gap-4">
      <h1 className="text-2xl font-bold">MCP-Chat</h1>
      <div className="flex flex-col gap-2">
        <input
          id="input_text"
          type="text"
          className="w-full p-2 border border-gray-300 rounded dark:disabled:bg-gray-700"
          placeholder="Type your message..."
        />
        <button
          type="button"
          className="px-4 py-2 text-white bg-blue-500 rounded hover:bg-blue-600 disabled:bg-gray-700"
          onClick={()=>{chatStart()}}
        > GO
        </button>
        <div className="my-2 p-2 bg-gray-100">
          {text}
        </div>
      </div>
    </div>
  );
}

  • プロンプト参考
サイコロを振ってください。1から6までの整数を返してください。