@olib-ai/owl-browser-mcp 1.0.2 → 1.0.4

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.
Files changed (2) hide show
  1. package/dist/index.js +258 -1
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -22529,6 +22529,204 @@ var openapi_default = {
22529
22529
  }
22530
22530
  }
22531
22531
  },
22532
+ "/api/execute/browser_extract_site": {
22533
+ post: {
22534
+ summary: "Browser Extract Site",
22535
+ description: "Extract content from multiple pages of a website. Crawls links starting from a URL and extracts content in the specified format. Returns a job_id immediately for async progress tracking. Use browser_extract_site_progress to monitor and browser_extract_site_result to get output.",
22536
+ tags: [
22537
+ "General"
22538
+ ],
22539
+ requestBody: {
22540
+ required: true,
22541
+ content: {
22542
+ "application/json": {
22543
+ schema: {
22544
+ type: "object",
22545
+ properties: {
22546
+ context_id: {
22547
+ type: "string",
22548
+ description: "The unique identifier of the browser context (e.g., 'ctx_000001')"
22549
+ },
22550
+ url: {
22551
+ type: "string",
22552
+ description: "Starting URL to begin extraction from"
22553
+ },
22554
+ depth: {
22555
+ type: "integer",
22556
+ description: "How many link levels to follow from the starting page. Default: 2. Higher values extract more pages but take longer"
22557
+ },
22558
+ max_pages: {
22559
+ type: "integer",
22560
+ description: "Maximum number of pages to extract. Default: 5. Limits total extraction to prevent runaway crawling"
22561
+ },
22562
+ follow_external: {
22563
+ type: "boolean",
22564
+ description: "Whether to follow links to external domains. Default: false. When false, only links within the same domain are followed"
22565
+ },
22566
+ output_format: {
22567
+ type: "string",
22568
+ description: "Output format for extracted content: 'markdown' (default), 'text', or 'json'. Markdown preserves structure, text is plain, JSON includes metadata",
22569
+ enum: [
22570
+ "markdown",
22571
+ "text",
22572
+ "json"
22573
+ ]
22574
+ },
22575
+ include_images: {
22576
+ type: "boolean",
22577
+ description: "Include resolved image URLs in output. Default: true"
22578
+ },
22579
+ include_metadata: {
22580
+ type: "boolean",
22581
+ description: "Include page title and description metadata. Default: true"
22582
+ },
22583
+ exclude_patterns: {
22584
+ type: "string",
22585
+ description: `JSON array of URL patterns to skip (glob patterns). Example: '["*/login*", "*/admin/*"]'`
22586
+ },
22587
+ timeout_per_page: {
22588
+ type: "integer",
22589
+ description: "Timeout per page in milliseconds. Default: 10000 (10 seconds)"
22590
+ }
22591
+ },
22592
+ required: [
22593
+ "context_id",
22594
+ "url"
22595
+ ]
22596
+ }
22597
+ }
22598
+ }
22599
+ },
22600
+ responses: {
22601
+ "200": {
22602
+ description: "Successful response"
22603
+ },
22604
+ "400": {
22605
+ description: "Bad request"
22606
+ },
22607
+ "401": {
22608
+ description: "Unauthorized"
22609
+ }
22610
+ }
22611
+ }
22612
+ },
22613
+ "/api/execute/browser_extract_site_progress": {
22614
+ post: {
22615
+ summary: "Browser Extract Site Progress",
22616
+ description: "Get progress of a site extraction job. Returns pages_completed, pages_total, current_url, and status. Status can be: 'running', 'completed', 'cancelled', or 'error'.",
22617
+ tags: [
22618
+ "General"
22619
+ ],
22620
+ requestBody: {
22621
+ required: true,
22622
+ content: {
22623
+ "application/json": {
22624
+ schema: {
22625
+ type: "object",
22626
+ properties: {
22627
+ job_id: {
22628
+ type: "string",
22629
+ description: "The job ID returned from browser_extract_site"
22630
+ }
22631
+ },
22632
+ required: [
22633
+ "job_id"
22634
+ ]
22635
+ }
22636
+ }
22637
+ }
22638
+ },
22639
+ responses: {
22640
+ "200": {
22641
+ description: "Successful response"
22642
+ },
22643
+ "400": {
22644
+ description: "Bad request"
22645
+ },
22646
+ "401": {
22647
+ description: "Unauthorized"
22648
+ }
22649
+ }
22650
+ }
22651
+ },
22652
+ "/api/execute/browser_extract_site_result": {
22653
+ post: {
22654
+ summary: "Browser Extract Site Result",
22655
+ description: "Get the result of a completed site extraction job. Returns the formatted content based on the output_format specified when starting the job (markdown, text, or json).",
22656
+ tags: [
22657
+ "General"
22658
+ ],
22659
+ requestBody: {
22660
+ required: true,
22661
+ content: {
22662
+ "application/json": {
22663
+ schema: {
22664
+ type: "object",
22665
+ properties: {
22666
+ job_id: {
22667
+ type: "string",
22668
+ description: "The job ID returned from browser_extract_site"
22669
+ }
22670
+ },
22671
+ required: [
22672
+ "job_id"
22673
+ ]
22674
+ }
22675
+ }
22676
+ }
22677
+ },
22678
+ responses: {
22679
+ "200": {
22680
+ description: "Successful response"
22681
+ },
22682
+ "400": {
22683
+ description: "Bad request"
22684
+ },
22685
+ "401": {
22686
+ description: "Unauthorized"
22687
+ }
22688
+ }
22689
+ }
22690
+ },
22691
+ "/api/execute/browser_extract_site_cancel": {
22692
+ post: {
22693
+ summary: "Browser Extract Site Cancel",
22694
+ description: "Cancel a running site extraction job. Returns success status.",
22695
+ tags: [
22696
+ "General"
22697
+ ],
22698
+ requestBody: {
22699
+ required: true,
22700
+ content: {
22701
+ "application/json": {
22702
+ schema: {
22703
+ type: "object",
22704
+ properties: {
22705
+ job_id: {
22706
+ type: "string",
22707
+ description: "The job ID to cancel"
22708
+ }
22709
+ },
22710
+ required: [
22711
+ "job_id"
22712
+ ]
22713
+ }
22714
+ }
22715
+ }
22716
+ },
22717
+ responses: {
22718
+ "200": {
22719
+ description: "Successful response"
22720
+ },
22721
+ "400": {
22722
+ description: "Bad request"
22723
+ },
22724
+ "401": {
22725
+ description: "Unauthorized"
22726
+ }
22727
+ }
22728
+ }
22729
+ },
22532
22730
  "/api/execute/browser_extract_json": {
22533
22731
  post: {
22534
22732
  summary: "Browser Extract Json",
@@ -26797,6 +26995,7 @@ var openapi_default = {
26797
26995
  var API_ENDPOINT = process.env.OWL_API_ENDPOINT || "http://127.0.0.1:8080";
26798
26996
  var API_TOKEN = process.env.OWL_API_TOKEN || "";
26799
26997
  var activeContexts = /* @__PURE__ */ new Map();
26998
+ var toolIntegerFields = /* @__PURE__ */ new Map();
26800
26999
  function convertOpenAPIToMCPTools(schema) {
26801
27000
  const tools = [];
26802
27001
  for (const [path, pathItem] of Object.entries(schema.paths)) {
@@ -26810,6 +27009,7 @@ function convertOpenAPIToMCPTools(schema) {
26810
27009
  };
26811
27010
  if (requestSchema?.properties) {
26812
27011
  const properties = {};
27012
+ const integerFields = /* @__PURE__ */ new Set();
26813
27013
  for (const [propName, propDef] of Object.entries(requestSchema.properties)) {
26814
27014
  const prop = {};
26815
27015
  if (propDef.type === "string") {
@@ -26821,6 +27021,9 @@ function convertOpenAPIToMCPTools(schema) {
26821
27021
  prop.type = "boolean";
26822
27022
  } else if (propDef.type === "number" || propDef.type === "integer") {
26823
27023
  prop.type = "number";
27024
+ if (propDef.type === "integer") {
27025
+ integerFields.add(propName);
27026
+ }
26824
27027
  } else if (propDef.type === "array") {
26825
27028
  prop.type = "array";
26826
27029
  if (propDef.items) {
@@ -26838,6 +27041,9 @@ function convertOpenAPIToMCPTools(schema) {
26838
27041
  properties[propName] = prop;
26839
27042
  }
26840
27043
  inputSchema.properties = properties;
27044
+ if (integerFields.size > 0) {
27045
+ toolIntegerFields.set(toolName, integerFields);
27046
+ }
26841
27047
  }
26842
27048
  if (requestSchema?.required && requestSchema.required.length > 0) {
26843
27049
  inputSchema.required = requestSchema.required;
@@ -26850,6 +27056,19 @@ function convertOpenAPIToMCPTools(schema) {
26850
27056
  }
26851
27057
  return tools;
26852
27058
  }
27059
+ function coerceIntegerFields(toolName, args) {
27060
+ const integerFields = toolIntegerFields.get(toolName);
27061
+ if (!integerFields || integerFields.size === 0) {
27062
+ return args;
27063
+ }
27064
+ const coerced = { ...args };
27065
+ for (const field of integerFields) {
27066
+ if (field in coerced && typeof coerced[field] === "number") {
27067
+ coerced[field] = Math.round(coerced[field]);
27068
+ }
27069
+ }
27070
+ return coerced;
27071
+ }
26853
27072
  async function callBrowserAPI(toolName, args) {
26854
27073
  const url2 = `${API_ENDPOINT}/api/execute/${toolName}`;
26855
27074
  const headers = {
@@ -26858,11 +27077,12 @@ async function callBrowserAPI(toolName, args) {
26858
27077
  if (API_TOKEN) {
26859
27078
  headers["Authorization"] = `Bearer ${API_TOKEN}`;
26860
27079
  }
27080
+ const coercedArgs = coerceIntegerFields(toolName, args);
26861
27081
  try {
26862
27082
  const response = await fetch(url2, {
26863
27083
  method: "POST",
26864
27084
  headers,
26865
- body: JSON.stringify(args)
27085
+ body: JSON.stringify(coercedArgs)
26866
27086
  });
26867
27087
  const contentType = response.headers.get("content-type") || "";
26868
27088
  let data;
@@ -26890,8 +27110,18 @@ async function callBrowserAPI(toolName, args) {
26890
27110
  };
26891
27111
  }
26892
27112
  }
27113
+ function isContextLimitError(result) {
27114
+ if (typeof result === "object" && result !== null) {
27115
+ const obj = result;
27116
+ return obj.error === true && obj.code === "CONTEXT_LIMIT_EXCEEDED";
27117
+ }
27118
+ return false;
27119
+ }
26893
27120
  function trackContext(toolName, args, result) {
26894
27121
  if (toolName === "browser_create_context" && typeof result === "object" && result !== null) {
27122
+ if (isContextLimitError(result)) {
27123
+ return;
27124
+ }
26895
27125
  const contextId = result.context_id;
26896
27126
  if (contextId) {
26897
27127
  activeContexts.set(contextId, { createdAt: /* @__PURE__ */ new Date() });
@@ -26921,6 +27151,33 @@ function formatResponse(toolName, result) {
26921
27151
  };
26922
27152
  }
26923
27153
  const data = result.data;
27154
+ if (typeof data === "object" && data !== null) {
27155
+ const dataObj = data;
27156
+ if (dataObj.success === true && typeof dataObj.result === "object" && dataObj.result !== null) {
27157
+ const innerResult = dataObj.result;
27158
+ if (innerResult.error === true && innerResult.code === "CONTEXT_LIMIT_EXCEEDED") {
27159
+ const details = innerResult.details || {};
27160
+ const errorMsg = innerResult.message || `Developer license context limit reached (${details.max_contexts || "unknown"} contexts). Close existing contexts or upgrade license.`;
27161
+ return {
27162
+ content: [
27163
+ {
27164
+ type: "text",
27165
+ text: JSON.stringify({
27166
+ success: false,
27167
+ error: errorMsg,
27168
+ code: "CONTEXT_LIMIT_EXCEEDED",
27169
+ details: {
27170
+ current_contexts: details.current_contexts,
27171
+ max_contexts: details.max_contexts,
27172
+ license_type: details.license_type || "developer"
27173
+ }
27174
+ }, null, 2)
27175
+ }
27176
+ ]
27177
+ };
27178
+ }
27179
+ }
27180
+ }
26924
27181
  const isImageTool = toolName === "browser_screenshot" || toolName === "browser_get_live_frame";
26925
27182
  if (isImageTool) {
26926
27183
  let base64Data = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@olib-ai/owl-browser-mcp",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "MCP server for Owl Browser HTTP API - 144 browser automation tools with anti-detection",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",