Monorepo for Aesthetic.Computer
aesthetic.computer
1// MCP Server for aesthetic.computer
2// Exposes tools, resources, and prompts for publishing and exploring pieces
3
4import { Server } from "@modelcontextprotocol/sdk/server/index.js";
5import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6import {
7 CallToolRequestSchema,
8 ListResourcesRequestSchema,
9 ListToolsRequestSchema,
10 ReadResourceRequestSchema,
11 ListPromptsRequestSchema,
12 GetPromptRequestSchema,
13} from "@modelcontextprotocol/sdk/types.js";
14
15// Import tools
16import { publishPieceTool, publishPiece } from "./tools/publish-piece.js";
17import { publishKidLispTool, publishKidLisp } from "./tools/publish-kidlisp.js";
18import { publishClockTool, publishClock } from "./tools/publish-clock.js";
19import { getAPIInfoTool, getAPIInfo } from "./tools/get-api-info.js";
20import {
21 previewKidLispTool,
22 previewKidLisp,
23} from "./tools/preview-kidlisp.js";
24
25// Import resources
26import {
27 pieceTemplateResource,
28 getPieceTemplate,
29} from "./resources/piece-template.js";
30import {
31 kidlispReferenceResource,
32 getKidLispReference,
33} from "./resources/kidlisp-reference.js";
34import {
35 pieceExamplesResource,
36 getPieceExamples,
37} from "./resources/piece-examples.js";
38
39// Import prompts
40import {
41 createPiecePrompt,
42 getCreatePiecePrompt,
43} from "./prompts/create-piece.js";
44import {
45 createKidLispPrompt,
46 getCreateKidLispPrompt,
47} from "./prompts/create-kidlisp.js";
48
49export class AestheticComputerServer {
50 private server: Server;
51 private token?: string;
52
53 constructor(token?: string) {
54 this.token = token;
55 this.server = new Server(
56 {
57 name: "aesthetic-computer",
58 version: "1.1.0",
59 },
60 {
61 capabilities: {
62 tools: {},
63 resources: {},
64 prompts: {},
65 },
66 }
67 );
68
69 this.setupHandlers();
70 }
71
72 private setupHandlers() {
73 // List available tools
74 this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
75 tools: [
76 publishPieceTool,
77 publishKidLispTool,
78 publishClockTool,
79 getAPIInfoTool,
80 previewKidLispTool,
81 ],
82 }));
83
84 // Handle tool calls
85 this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
86 const { name, arguments: args } = request.params;
87
88 try {
89 switch (name) {
90 case "publish_piece":
91 return {
92 content: [
93 {
94 type: "text",
95 text: JSON.stringify(
96 await publishPiece(
97 args as { source: string; name?: string },
98 this.token
99 ),
100 null,
101 2
102 ),
103 },
104 ],
105 };
106
107 case "publish_kidlisp":
108 return {
109 content: [
110 {
111 type: "text",
112 text: JSON.stringify(
113 await publishKidLisp(args as { source: string }, this.token),
114 null,
115 2
116 ),
117 },
118 ],
119 };
120
121 case "publish_clock":
122 return {
123 content: [
124 {
125 type: "text",
126 text: JSON.stringify(
127 await publishClock(args as { source: string }, this.token),
128 null,
129 2
130 ),
131 },
132 ],
133 };
134
135 case "get_api_info":
136 return {
137 content: [
138 {
139 type: "text",
140 text: JSON.stringify(await getAPIInfo(), null, 2),
141 },
142 ],
143 };
144
145 case "preview_kidlisp":
146 return {
147 content: [
148 {
149 type: "text",
150 text: JSON.stringify(
151 await previewKidLisp(args as { source: string }),
152 null,
153 2
154 ),
155 },
156 ],
157 };
158
159 default:
160 throw new Error(`Unknown tool: ${name}`);
161 }
162 } catch (error) {
163 return {
164 content: [
165 {
166 type: "text",
167 text: `Error: ${error instanceof Error ? error.message : String(error)}`,
168 },
169 ],
170 isError: true,
171 };
172 }
173 });
174
175 // List available resources
176 this.server.setRequestHandler(ListResourcesRequestSchema, async () => ({
177 resources: [
178 pieceTemplateResource,
179 kidlispReferenceResource,
180 pieceExamplesResource,
181 ],
182 }));
183
184 // Read resource content
185 this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
186 const { uri } = request.params;
187
188 switch (uri) {
189 case "aesthetic-computer://piece-template":
190 return {
191 contents: [
192 {
193 uri,
194 mimeType: "text/javascript",
195 text: getPieceTemplate(),
196 },
197 ],
198 };
199
200 case "aesthetic-computer://kidlisp-reference":
201 return {
202 contents: [
203 {
204 uri,
205 mimeType: "text/markdown",
206 text: getKidLispReference(),
207 },
208 ],
209 };
210
211 case "aesthetic-computer://piece-examples":
212 return {
213 contents: [
214 {
215 uri,
216 mimeType: "text/markdown",
217 text: getPieceExamples(),
218 },
219 ],
220 };
221
222 default:
223 throw new Error(`Unknown resource: ${uri}`);
224 }
225 });
226
227 // List available prompts
228 this.server.setRequestHandler(ListPromptsRequestSchema, async () => ({
229 prompts: [createPiecePrompt, createKidLispPrompt],
230 }));
231
232 // Get prompt content
233 this.server.setRequestHandler(GetPromptRequestSchema, async (request) => {
234 const { name, arguments: args } = request.params;
235
236 switch (name) {
237 case "create-piece":
238 return {
239 messages: [
240 {
241 role: "user",
242 content: {
243 type: "text",
244 text: getCreatePiecePrompt(
245 args as { name: string; description: string }
246 ),
247 },
248 },
249 ],
250 };
251
252 case "create-kidlisp":
253 return {
254 messages: [
255 {
256 role: "user",
257 content: {
258 type: "text",
259 text: getCreateKidLispPrompt(
260 args as { description: string }
261 ),
262 },
263 },
264 ],
265 };
266
267 default:
268 throw new Error(`Unknown prompt: ${name}`);
269 }
270 });
271 }
272
273 async run() {
274 const transport = new StdioServerTransport();
275 await this.server.connect(transport);
276 console.error("Aesthetic Computer MCP server running on stdio");
277 }
278}