@vampsieee/techterrain-mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025-2026 Romulus (https://techterrain.io)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,95 @@
1
+ # @vampsieee/techterrain-mcp
2
+
3
+ An [MCP server](https://modelcontextprotocol.io) that lets AI agents explore **3.4 million years of technology history** through [TechTerrain](https://techterrain.io) — a 3D voxel timeline of 1,200+ curated milestones.
4
+
5
+ Capture screenshots, generate GIFs, search any topic, and analyze cross-domain patterns — all from Claude, OpenClaw, or any MCP-compatible client.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npx -y @vampsieee/techterrain-mcp
11
+ ```
12
+
13
+ No API key required. The server connects to the public TechTerrain API at techterrain.io.
14
+
15
+ ## Claude Desktop
16
+
17
+ Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
18
+
19
+ ```json
20
+ {
21
+ "mcpServers": {
22
+ "techterrain": {
23
+ "command": "npx",
24
+ "args": ["-y", "@vampsieee/techterrain-mcp"]
25
+ }
26
+ }
27
+ }
28
+ ```
29
+
30
+ Restart Claude Desktop. You'll see the hammer icon with 7 tools.
31
+
32
+ ## Try It
33
+
34
+ > "Explore quantum computing on TechTerrain and take a screenshot"
35
+
36
+ > "Show me how AI and biotech have co-evolved, then generate a GIF orbiting the scene"
37
+
38
+ > "What causal relationships exist between technology categories?"
39
+
40
+ ## Tools
41
+
42
+ | Tool | Description | Cost |
43
+ |------|-------------|------|
44
+ | `capture_screenshot` | Headless screenshot via Cloudflare Browser Rendering → CDN URL | Free (35/hr) |
45
+ | `capture_gif` | Animated GIF generation (orbit or timelapse) → async job | Free (35/hr) |
46
+ | `get_gif_status` | Poll async GIF job progress and get result URL | Free |
47
+ | `explore_topic` | Search any topic → mapped milestones with years, categories, impact | LLM cost |
48
+ | `generate_insights` | LLM pattern analysis of a scene descriptor | LLM cost |
49
+ | `list_captures` | Browse the Agent Showcase gallery | Free |
50
+ | `get_insights` | Pre-computed Granger causality findings | Free |
51
+
52
+ ## Resources
53
+
54
+ | Resource | URI | Description |
55
+ |----------|-----|-------------|
56
+ | Agent API Docs | `techterrain://docs` | Full API reference with code examples |
57
+ | LLM Documentation | `techterrain://llms.txt` | Concise API reference for LLMs |
58
+ | Dataset | `techterrain://dataset` | Raw milestone dataset (1,200+ entries) |
59
+
60
+ ## Example Workflow
61
+
62
+ ```
63
+ User: "Show me how AI and biotech have co-evolved"
64
+
65
+ Agent:
66
+ 1. explore_topic("AI biotech co-evolution")
67
+ → Gets 15 milestones mapped across both categories
68
+ 2. capture_screenshot({
69
+ injectJs: "window.__techterrain.navigate({goto: 2010, categories: ['AI', 'Health']})",
70
+ caption: "AI-Biotech convergence 2010s"
71
+ })
72
+ → Gets CDN URL of the rendered view
73
+ 3. get_insights({ limit: 5 })
74
+ → Gets pre-computed causal findings about AI↔Health correlations
75
+ 4. Returns: image, milestones, and statistical insights to user
76
+ ```
77
+
78
+ ## Environment Variables
79
+
80
+ | Variable | Default | Description |
81
+ |----------|---------|-------------|
82
+ | `TECHTERRAIN_URL` | `https://techterrain.io` | Base URL of the TechTerrain instance |
83
+
84
+ ## Development
85
+
86
+ ```bash
87
+ cd mcp
88
+ pnpm install
89
+ npm run dev # Run with tsx (hot reload)
90
+ npm run build # Build distributable
91
+ ```
92
+
93
+ ## License
94
+
95
+ MIT
package/dist/index.js ADDED
@@ -0,0 +1,336 @@
1
+ #!/usr/bin/env node
2
+
3
+ // techterrain-mcp-server.ts
4
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6
+ import { z } from "zod";
7
+ var BASE_URL = process.env.TECHTERRAIN_URL || "https://techterrain.io";
8
+ var TRPC_URL = `${BASE_URL}/api/trpc`;
9
+ async function trpcMutate(procedure, input) {
10
+ const res = await fetch(`${TRPC_URL}/${procedure}?batch=1`, {
11
+ method: "POST",
12
+ headers: { "Content-Type": "application/json" },
13
+ body: JSON.stringify({ "0": { json: input } })
14
+ });
15
+ if (!res.ok) {
16
+ const text = await res.text();
17
+ throw new Error(`tRPC ${procedure} failed (${res.status}): ${text}`);
18
+ }
19
+ const batch = await res.json();
20
+ if (batch[0]?.error) {
21
+ throw new Error(`tRPC ${procedure} error: ${JSON.stringify(batch[0].error)}`);
22
+ }
23
+ return batch[0]?.result?.data?.json;
24
+ }
25
+ async function trpcQuery(procedure, input) {
26
+ const inputParam = input ? `&input=${encodeURIComponent(JSON.stringify({ "0": { json: input } }))}` : `&input=${encodeURIComponent(JSON.stringify({ "0": { json: void 0 } }))}`;
27
+ const res = await fetch(`${TRPC_URL}/${procedure}?batch=1${inputParam}`, {
28
+ method: "GET",
29
+ headers: { "Content-Type": "application/json" }
30
+ });
31
+ if (!res.ok) {
32
+ const text = await res.text();
33
+ throw new Error(`tRPC ${procedure} failed (${res.status}): ${text}`);
34
+ }
35
+ const batch = await res.json();
36
+ if (batch[0]?.error) {
37
+ throw new Error(`tRPC ${procedure} error: ${JSON.stringify(batch[0].error)}`);
38
+ }
39
+ return batch[0]?.result?.data?.json;
40
+ }
41
+ async function fetchText(path) {
42
+ const res = await fetch(`${BASE_URL}${path}`);
43
+ if (!res.ok) throw new Error(`Failed to fetch ${path}: ${res.status}`);
44
+ return res.text();
45
+ }
46
+ var server = new McpServer({
47
+ name: "techterrain",
48
+ version: "1.0.0"
49
+ });
50
+ server.resource(
51
+ "docs",
52
+ "techterrain://docs",
53
+ {
54
+ description: "TechTerrain Agent API documentation \u2014 full reference with code examples for all endpoints",
55
+ mimeType: "text/html"
56
+ },
57
+ async () => ({
58
+ contents: [{
59
+ uri: "techterrain://docs",
60
+ text: await fetchText("/agent-docs.html"),
61
+ mimeType: "text/html"
62
+ }]
63
+ })
64
+ );
65
+ server.resource(
66
+ "llms-txt",
67
+ "techterrain://llms.txt",
68
+ {
69
+ description: "LLM-optimized documentation for TechTerrain \u2014 concise API reference, recommended workflows, and data coverage",
70
+ mimeType: "text/plain"
71
+ },
72
+ async () => ({
73
+ contents: [{
74
+ uri: "techterrain://llms.txt",
75
+ text: await fetchText("/llms.txt"),
76
+ mimeType: "text/plain"
77
+ }]
78
+ })
79
+ );
80
+ server.resource(
81
+ "dataset",
82
+ "techterrain://dataset",
83
+ {
84
+ description: "Raw TechTerrain milestone dataset \u2014 1,200+ curated technology milestones across 7 categories spanning 3.4 million years",
85
+ mimeType: "application/json"
86
+ },
87
+ async () => ({
88
+ contents: [{
89
+ uri: "techterrain://dataset",
90
+ text: await fetchText("/tech_data.json"),
91
+ mimeType: "application/json"
92
+ }]
93
+ })
94
+ );
95
+ server.tool(
96
+ "capture_screenshot",
97
+ `Render a headless screenshot of TechTerrain via Cloudflare Browser Rendering.
98
+ Returns a public CDN URL of the captured image. No client-side browser needed.
99
+ Use injectJs to position the camera, navigate to a year, or trigger UI actions before capture.
100
+ Rate limit: 35 renders/hour.`,
101
+ {
102
+ path: z.string().default("/").describe('URL path, e.g. "/" or "/explore/1900-2020/Computing,AI"'),
103
+ width: z.number().min(320).max(3840).default(1280).describe("Viewport width in pixels"),
104
+ height: z.number().min(240).max(2160).default(720).describe("Viewport height in pixels"),
105
+ format: z.enum(["png", "jpeg"]).default("png").describe("Image format"),
106
+ injectJs: z.string().optional().describe('JavaScript to inject after scene ready. Example: "window.__techterrain.navigate({goto: 1969})"'),
107
+ waitForOverlays: z.boolean().default(false).describe("Wait for search overlay data to finish loading before capture (set true when injectJs triggers a search)"),
108
+ caption: z.string().optional().describe("Caption for the showcase gallery"),
109
+ authorName: z.string().optional().describe("Author name for attribution")
110
+ },
111
+ async (args) => {
112
+ try {
113
+ const result = await trpcMutate("agent.renderUrl", args);
114
+ return {
115
+ content: [{
116
+ type: "text",
117
+ text: JSON.stringify({
118
+ success: true,
119
+ imageUrl: result.url,
120
+ browserMsUsed: result.browserMsUsed,
121
+ message: "Screenshot captured and uploaded to CDN."
122
+ }, null, 2)
123
+ }]
124
+ };
125
+ } catch (err) {
126
+ return {
127
+ content: [{ type: "text", text: `Error: ${err.message}` }],
128
+ isError: true
129
+ };
130
+ }
131
+ }
132
+ );
133
+ server.tool(
134
+ "capture_gif",
135
+ `Generate an animated GIF of TechTerrain via server-side Cloudflare Browser Rendering.
136
+ Returns a jobId immediately \u2014 poll with get_gif_status to check completion.
137
+ Two modes: "orbit" rotates the camera around the scene, "timeLapse" scrubs through years.
138
+ Rate limit: 35 renders/hour (each frame counts as one render).`,
139
+ {
140
+ path: z.string().default("/").describe("URL path to render"),
141
+ mode: z.enum(["orbit", "timeLapse"]).default("orbit").describe("orbit = camera rotation, timeLapse = year scrubbing"),
142
+ frameCount: z.number().min(2).max(24).default(12).describe("Number of frames in the GIF"),
143
+ totalRotationDeg: z.number().min(10).max(360).default(360).describe("Total camera rotation in degrees (orbit mode only)"),
144
+ startYear: z.number().optional().describe("Start year for timeLapse mode (supports negative/BCE values like -3400000)"),
145
+ endYear: z.number().optional().describe("End year for timeLapse mode"),
146
+ width: z.number().min(320).max(1920).default(800).describe("Frame width in pixels"),
147
+ height: z.number().min(240).max(1080).default(600).describe("Frame height in pixels"),
148
+ frameDelay: z.number().min(50).max(2e3).default(200).describe("Delay between frames in ms"),
149
+ injectJs: z.string().optional().describe("JavaScript to inject before capture begins"),
150
+ caption: z.string().optional().describe("Caption for the showcase gallery"),
151
+ authorName: z.string().optional().describe("Author name for attribution")
152
+ },
153
+ async (args) => {
154
+ try {
155
+ const result = await trpcMutate("agent.renderGif", args);
156
+ return {
157
+ content: [{
158
+ type: "text",
159
+ text: JSON.stringify({
160
+ success: true,
161
+ jobId: result.jobId,
162
+ status: result.status,
163
+ message: "GIF generation started. Poll with get_gif_status tool using this jobId."
164
+ }, null, 2)
165
+ }]
166
+ };
167
+ } catch (err) {
168
+ return {
169
+ content: [{ type: "text", text: `Error: ${err.message}` }],
170
+ isError: true
171
+ };
172
+ }
173
+ }
174
+ );
175
+ server.tool(
176
+ "get_gif_status",
177
+ `Poll the status of an async GIF generation job.
178
+ Returns progress percentage, frames captured, and the final CDN URL when complete.`,
179
+ {
180
+ jobId: z.string().describe("The jobId returned by capture_gif")
181
+ },
182
+ async (args) => {
183
+ try {
184
+ const result = await trpcQuery("agent.renderGifStatus", args);
185
+ return {
186
+ content: [{
187
+ type: "text",
188
+ text: JSON.stringify({
189
+ jobId: result.jobId,
190
+ status: result.status,
191
+ progress: `${result.progress}%`,
192
+ framesCaptured: result.framesCaptured,
193
+ framesTotalRequested: result.framesTotalRequested,
194
+ ...result.resultUrl ? { gifUrl: result.resultUrl } : {},
195
+ ...result.browserMsUsed ? { browserMsUsed: result.browserMsUsed } : {},
196
+ ...result.errorMessage ? { error: result.errorMessage } : {}
197
+ }, null, 2)
198
+ }]
199
+ };
200
+ } catch (err) {
201
+ return {
202
+ content: [{ type: "text", text: `Error: ${err.message}` }],
203
+ isError: true
204
+ };
205
+ }
206
+ }
207
+ );
208
+ server.tool(
209
+ "explore_topic",
210
+ `Search any topic and get it mapped onto TechTerrain's timeline.
211
+ Uses LLM synthesis to find relevant technology milestones for any subject \u2014
212
+ people, companies, concepts, events, or scientific fields.
213
+ Returns structured milestone data with years, categories, impact scores, and source URLs.`,
214
+ {
215
+ query: z.string().describe('Topic to explore, e.g. "quantum computing", "Nikola Tesla", "CRISPR gene editing"')
216
+ },
217
+ async (args) => {
218
+ try {
219
+ const result = await trpcMutate("search.explore", { query: args.query });
220
+ return {
221
+ content: [{
222
+ type: "text",
223
+ text: JSON.stringify({
224
+ query: result.query,
225
+ summary: result.summary,
226
+ milestoneCount: result.milestones.length,
227
+ milestones: result.milestones
228
+ }, null, 2)
229
+ }]
230
+ };
231
+ } catch (err) {
232
+ return {
233
+ content: [{ type: "text", text: `Error: ${err.message}` }],
234
+ isError: true
235
+ };
236
+ }
237
+ }
238
+ );
239
+ server.tool(
240
+ "generate_insights",
241
+ `Generate LLM-powered pattern analysis from a TechTerrain scene descriptor.
242
+ Pass the output of getSceneDescriptor() to get cross-domain correlations,
243
+ geographic clustering patterns, and acceleration/deceleration insights.
244
+ Each insight includes confidence rating and suggested camera view.`,
245
+ {
246
+ sceneDescriptor: z.any().describe("Scene descriptor JSON from window.__techterrain.getSceneDescriptor()"),
247
+ focusArea: z.string().optional().describe('Optional focus, e.g. "cross-category correlations" or "geographic clustering"')
248
+ },
249
+ async (args) => {
250
+ try {
251
+ const result = await trpcMutate("agent.generateInsights", args);
252
+ return {
253
+ content: [{
254
+ type: "text",
255
+ text: JSON.stringify(result, null, 2)
256
+ }]
257
+ };
258
+ } catch (err) {
259
+ return {
260
+ content: [{ type: "text", text: `Error: ${err.message}` }],
261
+ isError: true
262
+ };
263
+ }
264
+ }
265
+ );
266
+ server.tool(
267
+ "list_captures",
268
+ `Browse the TechTerrain Agent Showcase gallery.
269
+ Returns recent agent-generated screenshots and GIFs with metadata, captions, and CDN URLs.`,
270
+ {
271
+ type: z.enum(["screenshot", "gif", "render", "all"]).default("all").describe("Filter by capture type"),
272
+ featuredOnly: z.boolean().default(false).describe("Only return featured captures"),
273
+ limit: z.number().min(1).max(50).default(20).describe("Number of captures to return")
274
+ },
275
+ async (args) => {
276
+ try {
277
+ const result = await trpcQuery("agent.listCaptures", args);
278
+ return {
279
+ content: [{
280
+ type: "text",
281
+ text: JSON.stringify({
282
+ total: result.total,
283
+ captures: result.captures.map((c) => ({
284
+ id: c.id,
285
+ imageUrl: c.url,
286
+ type: c.captureType,
287
+ author: c.authorName,
288
+ caption: c.caption,
289
+ featured: c.featured
290
+ }))
291
+ }, null, 2)
292
+ }]
293
+ };
294
+ } catch (err) {
295
+ return {
296
+ content: [{ type: "text", text: `Error: ${err.message}` }],
297
+ isError: true
298
+ };
299
+ }
300
+ }
301
+ );
302
+ server.tool(
303
+ "get_insights",
304
+ `Get pre-computed Granger causality findings from TechTerrain's Insights Engine.
305
+ Returns statistically significant causal relationships between technology categories
306
+ and economic indicators, with human-readable narrations.
307
+ Free \u2014 no LLM cost (findings are pre-computed via batch analysis).`,
308
+ {
309
+ limit: z.number().min(1).max(50).default(10).describe("Number of findings to return")
310
+ },
311
+ async (args) => {
312
+ try {
313
+ const result = await trpcQuery("insights.getLatest", { limit: args.limit });
314
+ return {
315
+ content: [{
316
+ type: "text",
317
+ text: JSON.stringify(result, null, 2)
318
+ }]
319
+ };
320
+ } catch (err) {
321
+ return {
322
+ content: [{ type: "text", text: `Error: ${err.message}` }],
323
+ isError: true
324
+ };
325
+ }
326
+ }
327
+ );
328
+ async function main() {
329
+ const transport = new StdioServerTransport();
330
+ await server.connect(transport);
331
+ console.error("TechTerrain MCP server running on stdio");
332
+ }
333
+ main().catch((err) => {
334
+ console.error("Fatal error:", err);
335
+ process.exit(1);
336
+ });
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@vampsieee/techterrain-mcp",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for TechTerrain — explore 3.4 million years of technology history through AI agents",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "techterrain-mcp": "dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "README.md",
13
+ "LICENSE",
14
+ "server.json"
15
+ ],
16
+ "scripts": {
17
+ "build": "esbuild techterrain-mcp-server.ts --bundle --platform=node --format=esm --target=node18 --outfile=dist/index.js --banner:js='#!/usr/bin/env node' --packages=external",
18
+ "start": "node dist/index.js",
19
+ "dev": "npx tsx techterrain-mcp-server.ts",
20
+ "prepublishOnly": "npm run build"
21
+ },
22
+ "keywords": [
23
+ "mcp",
24
+ "model-context-protocol",
25
+ "techterrain",
26
+ "data-visualization",
27
+ "technology-history",
28
+ "ai-agent",
29
+ "claude",
30
+ "timeline"
31
+ ],
32
+ "author": "Romulus (https://techterrain.io)",
33
+ "license": "MIT",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "https://github.com/vampsieee/tech-terrain-voxel.git",
37
+ "directory": "mcp"
38
+ },
39
+ "homepage": "https://techterrain.io",
40
+ "engines": {
41
+ "node": ">=18.0.0"
42
+ },
43
+ "dependencies": {
44
+ "@modelcontextprotocol/sdk": "^1.26.0",
45
+ "zod": "^4.1.12"
46
+ },
47
+ "devDependencies": {
48
+ "esbuild": "^0.25.0",
49
+ "tsx": "^4.0.0",
50
+ "typescript": "^5.9.0"
51
+ }
52
+ }
package/server.json ADDED
@@ -0,0 +1,76 @@
1
+ {
2
+ "$schema": "https://registry.modelcontextprotocol.io/schemas/server.json",
3
+ "name": "techterrain",
4
+ "display_name": "TechTerrain",
5
+ "description": "Explore 3.4 million years of technology history through AI agents. Capture screenshots, generate GIFs, search topics, and analyze patterns across 1,200+ curated milestones in a 3D voxel timeline.",
6
+ "homepage": "https://techterrain.io",
7
+ "repository": "https://github.com/vampsieee/tech-terrain-voxel",
8
+ "icon": "https://techterrain.io/favicon.ico",
9
+ "category": "data-visualization",
10
+ "tags": [
11
+ "data-visualization",
12
+ "technology-history",
13
+ "timeline",
14
+ "3d",
15
+ "voxel",
16
+ "screenshot",
17
+ "gif",
18
+ "research",
19
+ "education"
20
+ ],
21
+ "installations": {
22
+ "npm": {
23
+ "type": "npm",
24
+ "package_name": "@vampsieee/techterrain-mcp",
25
+ "command": "npx",
26
+ "args": ["-y", "@vampsieee/techterrain-mcp"]
27
+ }
28
+ },
29
+ "tools": [
30
+ {
31
+ "name": "capture_screenshot",
32
+ "description": "Render a headless screenshot of TechTerrain via Cloudflare Browser Rendering. Returns a public CDN URL."
33
+ },
34
+ {
35
+ "name": "capture_gif",
36
+ "description": "Generate an animated GIF (orbit or timelapse). Returns a jobId for async polling."
37
+ },
38
+ {
39
+ "name": "get_gif_status",
40
+ "description": "Poll the status of an async GIF generation job."
41
+ },
42
+ {
43
+ "name": "explore_topic",
44
+ "description": "Search any topic and get it mapped onto TechTerrain's timeline with structured milestone data."
45
+ },
46
+ {
47
+ "name": "generate_insights",
48
+ "description": "LLM-powered pattern analysis of a TechTerrain scene descriptor."
49
+ },
50
+ {
51
+ "name": "list_captures",
52
+ "description": "Browse the Agent Showcase gallery of agent-generated screenshots and GIFs."
53
+ },
54
+ {
55
+ "name": "get_insights",
56
+ "description": "Get pre-computed Granger causality findings between technology categories and economic indicators."
57
+ }
58
+ ],
59
+ "resources": [
60
+ {
61
+ "name": "docs",
62
+ "uri": "techterrain://docs",
63
+ "description": "Full Agent API documentation with code examples"
64
+ },
65
+ {
66
+ "name": "llms-txt",
67
+ "uri": "techterrain://llms.txt",
68
+ "description": "LLM-optimized concise API reference"
69
+ },
70
+ {
71
+ "name": "dataset",
72
+ "uri": "techterrain://dataset",
73
+ "description": "Raw milestone dataset — 1,200+ curated technology milestones across 7 categories"
74
+ }
75
+ ]
76
+ }