Sign In

@arcede/air-mcp

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@arcede/air-mcp - npm Package Compare versions

Comparing version
0.1.0
to
0.2.0
+146
-14
dist/server.js
#!/usr/bin/env node
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));

@@ -48,8 +70,12 @@ // src/server.ts

url: import_zod.z.string().url().describe("The URL to extract data from"),
force: import_zod.z.boolean().optional().describe("Bypass cache for fresh extraction (costs 1.0 credit vs 0.1 for cached)")
force: import_zod.z.boolean().optional().describe("Bypass cache for fresh extraction (costs 1.0 credit vs 0.1 for cached)"),
full_text: import_zod.z.boolean().optional().describe("Return the full page plaintext in content.text (default: false). Useful for document import pipelines.")
},
async ({ url, force }) => {
async ({ url, force, full_text }) => {
const options = {};
if (force) options.force = true;
if (full_text) options.fullText = true;
const result = await apiRequest("POST", "/v1/extract", {
url,
options: { force: force || false }
options
});

@@ -66,3 +92,3 @@ if (!result.success) {

const data = result.data;
const summary = [
const lines = [
`# ${data.title}`,

@@ -79,7 +105,11 @@ data.description ? `

Credits used: ${result.credits_used} | Remaining: ${result.credits_remaining}`
].filter(Boolean).join("\n");
return {
content: [
{ type: "text", text: summary },
{ type: "text", text: `
].filter(Boolean);
if (full_text && data.content?.text) {
lines.push("", "## Full Text", "", data.content.text);
}
const contentBlocks = [
{ type: "text", text: lines.join("\n") }
];
if (!full_text) {
contentBlocks.push({ type: "text", text: `

@@ -89,5 +119,5 @@ ## Raw Data

${JSON.stringify(data, null, 2)}
\`\`\`` }
]
};
\`\`\`` });
}
return { content: contentBlocks };
}

@@ -191,2 +221,103 @@ );

);
server.tool(
"extract_content",
"Extract text from a file (PDF, DOCX, PPTX, XLSX, CSV, TXT, MD, HTML, EML). Returns structured sections and full text. Any agent can use this \u2014 no browser needed. Use for document import: extract_content \u2192 research_import.",
{
file_url: import_zod.z.string().optional().describe("URL to fetch the file from (HTTP/HTTPS). Provide file_url or file_path, not both."),
file_path: import_zod.z.string().optional().describe("Local file path (for desktop agents). Provide file_url or file_path, not both."),
force_ocr: import_zod.z.boolean().optional().describe("Force OCR for scanned PDFs (default: false)")
},
async ({ file_url, file_path, force_ocr }) => {
if (!file_url && !file_path) {
return {
content: [{ type: "text", text: "Error: Provide either file_url or file_path." }],
isError: true
};
}
let fileBlob;
let fileName;
if (file_url) {
try {
const resp = await fetch(file_url, { signal: AbortSignal.timeout(3e4) });
if (!resp.ok) {
return {
content: [{ type: "text", text: `Failed to fetch file: ${resp.status} ${resp.statusText}` }],
isError: true
};
}
fileBlob = await resp.blob();
fileName = new URL(file_url).pathname.split("/").pop() || "document";
} catch (err) {
return {
content: [{ type: "text", text: `Failed to fetch file: ${err?.message || "Unknown error"}` }],
isError: true
};
}
} else {
try {
const { promises: fsp } = await import("fs");
const path = await import("path");
const buffer = await fsp.readFile(file_path);
fileBlob = new Blob([buffer]);
fileName = path.basename(file_path);
} catch (err) {
return {
content: [{ type: "text", text: `Failed to read file: ${err?.message || "Unknown error"}` }],
isError: true
};
}
}
const formData = new FormData();
formData.append("file", fileBlob, fileName);
if (force_ocr) formData.append("force_ocr", "true");
let result;
try {
const resp = await fetch(`${API_BASE}/v1/extract-content`, {
method: "POST",
headers: { "Authorization": `Bearer ${API_KEY}` },
body: formData,
signal: AbortSignal.timeout(12e4)
});
try {
result = await resp.json();
} catch {
return {
content: [{ type: "text", text: `Extraction failed: API returned ${resp.status} with non-JSON response` }],
isError: true
};
}
} catch (err) {
return {
content: [{ type: "text", text: `Extraction failed: ${err?.message || "Service unavailable"}` }],
isError: true
};
}
if (!result.success) {
return {
content: [{ type: "text", text: `Extraction failed: ${result.error || result.message}` }],
isError: true
};
}
const data = result.data;
const diag = data.diagnostics;
const lines = [
`# ${data.title || fileName}`,
"",
`Source: ${file_url || file_path}`,
`Parser: ${diag?.extractionMethod || "unknown"}`,
`Confidence: ${diag?.confidenceScore ? (diag.confidenceScore * 100).toFixed(0) + "%" : "unknown"}`,
`Sections: ${diag?.itemsExtracted || 0}`,
`Time: ${diag?.extractionTimeMs || 0}ms`
];
if (data.metadata?.pageCount) lines.push(`Pages: ${data.metadata.pageCount}`);
if (data.metadata?.wordCount) lines.push(`Words: ${data.metadata.wordCount}`);
if (result.credits_used !== void 0) {
lines.push(`Credits: ${result.credits_used} used | ${result.credits_remaining ?? "?"} remaining`);
}
if (data.content?.text) {
lines.push("", "## Full Text", "", data.content.text);
}
return { content: [{ type: "text", text: lines.join("\n") }] };
}
);
server.resource(

@@ -204,4 +335,5 @@ "api-status",

"Endpoints:",
" POST /v1/extract \u2014 Extract structured data from a URL (1.0 credits)",
" POST /v1/capabilities \u2014 Query site capabilities (0.25 credits)",
" POST /v1/extract \u2014 Extract structured data from a URL (1.0 credits)",
" POST /v1/extract-content \u2014 Extract text from files (PDF, DOCX, etc.)",
" POST /v1/capabilities \u2014 Query site capabilities (0.25 credits)",
"",

@@ -208,0 +340,0 @@ "Pricing:",

+26
-12
{
"name": "@arcede/air-mcp",
"version": "0.1.0",
"version": "0.2.0",
"description": "MCP server for the Agent Internet Runtime — extract web data and query site capabilities from any AI coding tool",

@@ -14,19 +14,33 @@ "bin": {

"dependencies": {
"@modelcontextprotocol/sdk": "^1.0.0",
"zod": "^3.23.0"
"@modelcontextprotocol/sdk": "^1.28.0",
"zod": "^3.25.76"
},
"devDependencies": {
"tsup": "^8.0.0",
"tsx": "^4.7.0",
"typescript": "^5.3.0",
"@types/node": "^20.11.0"
"tsup": "^8.5.1",
"tsx": "^4.21.0",
"typescript": "^5.9.3",
"@types/node": "^20.19.37"
},
"keywords": [
"mcp", "model-context-protocol", "air", "extract", "capabilities",
"web-extraction", "ai-agent", "agent-internet-runtime",
"claude-code", "cursor", "windsurf"
"mcp",
"model-context-protocol",
"air",
"extract",
"capabilities",
"web-extraction",
"ai-agent",
"agent-internet-runtime",
"claude-code",
"cursor",
"windsurf"
],
"license": "MIT",
"engines": { "node": ">=18" },
"files": ["dist/", "README.md", "LICENSE"]
"engines": {
"node": ">=18"
},
"files": [
"dist/",
"README.md",
"LICENSE"
]
}