7// Initialize Notion client
8const notion = new Client({
9auth: Deno.env.get("NOTION_API_KEY"),
10});
11
7// Initialize Notion client
8const notion = new Client({
9auth: Deno.env.get("NOTION_API_KEY"),
10});
11
7// Initialize Notion client
8const notion = new Client({
9auth: Deno.env.get("NOTION_API_KEY"),
10});
11
ValTownForNotionauth.ts2 matches
1export default async (c, next) => {
2const secret = c.req.header("x-api-key");
3if (secret !== Deno.env.get("X_API_KEY")) {
4return c.text("Unauthorized", 401);
5}
GlancerdemoCache.ts1 match
5// Initialize Notion client
6const notion = new Client({
7auth: Deno.env.get("NOTION_API_KEY"),
8});
9
endpointsget_vals_endpoints.tsx9 matches
1export default async function(req: Request) {
2try {
3const apiKey = Deno.env.get("VALTOWN_API_TOKEN");
45if (!apiKey) {
6return new Response(
7JSON.stringify({ error: "VALTOWN_API_TOKEN not found" }, null, 2),
8{ status: 400, headers: { "Content-Type": "application/json" } },
9);
1112// Get my vals using the authenticated /me/vals endpoint
13const valsResponse = await fetch("https://api.val.town/v2/me/vals", {
14headers: {
15"Authorization": `Bearer ${apiKey}`,
16"Content-Type": "application/json",
17},
20if (!valsResponse.ok) {
21const errorText = await valsResponse.text();
22console.log("API Error response:", errorText);
23throw new Error(
24`Failed to fetch vals: ${valsResponse.status} ${valsResponse.statusText}. Response: ${errorText}`,
42for (const val of vals) {
43try {
44// Use the files API to get the actual file structure
45const filesResponse = await fetch(
46`https://api.val.town/v2/vals/${val.id}/files?path=&recursive=true&limit=100`,
47{
48headers: {
49"Authorization": `Bearer ${apiKey}`,
50"Content-Type": "application/json",
51},
57
58// Get location first
59const locationResponse = await fetch("/api/location");
60const locationData = await locationResponse.json();
61setLocation(locationData);
7172const fetchWeatherData = async (lat: number, lon: number) => {
73const response = await fetch(`/api/weather?lat=${lat}&lon=${lon}`);
74const data = await response.json();
75
1/** @jsxImportSource https://esm.sh/react@18.2.0 */
2import React, { useEffect, useRef, useState } from "https://esm.sh/react@18.2.0?deps=react@18.2.0";
3import { ApiKeyInput } from "./ApiKeyInput.tsx";
4import { ChatInterface } from "./ChatInterface.tsx";
5import { MCPClient } from "./MCPClient.tsx";
2324export function App() {
25const [apiKey, setApiKey] = useState<string>("");
26const [messages, setMessages] = useState<Message[]>([]);
27const [isLoading, setIsLoading] = useState(false);
29const [availableTools, setAvailableTools] = useState<any[]>([]);
3031// Initialize MCP client and load API key from localStorage
32useEffect(() => {
33const savedApiKey = localStorage.getItem("anthropic_api_key");
34if (savedApiKey) {
35setApiKey(savedApiKey);
36}
3753role: "system",
54content:
55"Welcome to the Val Town MCP Client Demo! This chat interface connects to Claude via the Anthropic API and uses the Val Town MCP server to execute tools. Enter your Anthropic API key to get started.",
56timestamp: new Date(),
57}]);
58}, []);
5960const handleApiKeyChange = (key: string) => {
61setApiKey(key);
62localStorage.setItem("anthropic_api_key", key);
63};
6465const sendMessage = async (content: string) => {
66if (!apiKey.trim()) {
67alert("Please enter your Anthropic API key first");
68return;
69}
93When you need to use these tools, I will execute them for you and provide the results. Be helpful and use the tools when appropriate to assist the user.`;
9495// Call Anthropic API
96const response = await fetch("https://api.anthropic.com/v1/messages", {
97method: "POST",
98headers: {
99"Content-Type": "application/json",
100"x-api-key": apiKey,
101"anthropic-version": "2023-06-01",
102"anthropic-dangerous-direct-browser-access": "true",
125if (!response.ok) {
126const errorData = await response.json();
127throw new Error(`Anthropic API error: ${errorData.error?.message || response.statusText}`);
128}
129208209<div className="grid gap-6">
210<ApiKeyInput
211apiKey={apiKey}
212onApiKeyChange={handleApiKeyChange}
213/>
214
MCPApiKeyInput.tsx17 matches
2import React, { useState } from "https://esm.sh/react@18.2.0?deps=react@18.2.0";
34interface ApiKeyInputProps {
5apiKey: string;
6onApiKeyChange: (key: string) => void;
7}
89export function ApiKeyInput({ apiKey, onApiKeyChange }: ApiKeyInputProps) {
10const [isVisible, setIsVisible] = useState(false);
11const [tempKey, setTempKey] = useState(apiKey);
1213const handleSave = () => {
14onApiKeyChange(tempKey);
15};
1617const handleClear = () => {
18setTempKey('');
19onApiKeyChange('');
20localStorage.removeItem('anthropic_api_key');
21};
2223return (
24<div className="bg-white rounded-lg shadow-md p-6">
25<h2 className="text-2xl font-semibold text-gray-800 mb-4">🔑 Anthropic API Key</h2>
26
27<div className="space-y-4">
28<div>
29<label htmlFor="apiKey" className="block text-sm font-medium text-gray-700 mb-2">
30Enter your Anthropic API Key
31</label>
32<div className="flex gap-2">
33<div className="flex-1 relative">
34<input
35id="apiKey"
36type={isVisible ? "text" : "password"}
37value={tempKey}
38onChange={(e) => setTempKey(e.target.value)}
39placeholder="sk-ant-api03-..."
40className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
41/>
67<p className="mb-2">
68<strong>Status:</strong>{' '}
69<span className={apiKey ? 'text-green-600' : 'text-red-600'}>
70{apiKey ? '✅ API key configured' : '❌ No API key set'}
71</span>
72</p>
73<p className="mb-2">
74Your API key is stored locally in your browser and sent directly to Anthropic's API.
75</p>
76<p>
77Get your API key from{' '}
78<a
79href="https://console.anthropic.com/account/keys"
MCPChatInterface.tsx1 match
125<div className="flex items-center gap-2">
126<span>{getMessageIcon(message.role)}</span>
127<span className="font-semibold capitalize">{message.role}</span>
128</div>
129<span className="text-xs text-gray-500">