@capitalthought/agentsfirst-mcp 0.1.1 → 0.1.2

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/dist/probe.d.ts CHANGED
@@ -168,6 +168,7 @@ export interface WebsiteSignals {
168
168
  ai_agents_addressed: string[];
169
169
  address_count: number;
170
170
  blanket_disallow: boolean;
171
+ content_signal_directives?: Record<string, string>;
171
172
  };
172
173
  markdown_negotiation: {
173
174
  requested?: string;
package/dist/probe.js CHANGED
@@ -379,10 +379,26 @@ export async function probeWebsite(url) {
379
379
  'cohere-ai',
380
380
  ];
381
381
  const declared = aiAgents.filter((ua) => new RegExp(`User-agent:\\s*${ua}`, 'i').test(robotsBody));
382
+ // Content-Signal directive (Cloudflare's emerging AI-policy convention).
383
+ // Format: `Content-Signal: ai-train=yes, search=yes, ai-input=yes`
384
+ const contentSignalLines = robotsBody.match(/^Content-Signal:\s*(.+)$/gim) ?? [];
385
+ const directives = {};
386
+ for (const line of contentSignalLines) {
387
+ const m = line.match(/^Content-Signal:\s*(.+)$/i);
388
+ const captured = m?.[1];
389
+ if (!captured)
390
+ continue;
391
+ for (const pair of captured.split(',')) {
392
+ const [k, v] = pair.split('=').map((s) => s.trim().toLowerCase());
393
+ if (k && v)
394
+ directives[k] = v;
395
+ }
396
+ }
382
397
  out.signals.robots_analysis = {
383
398
  ai_agents_addressed: declared,
384
399
  address_count: declared.length,
385
400
  blanket_disallow: /User-agent:\s*\*[\s\S]*?Disallow:\s*\//i.test(robotsBody),
401
+ ...(Object.keys(directives).length > 0 && { content_signal_directives: directives }),
386
402
  };
387
403
  }
388
404
  const homepageBody = out.signals.homepage?.body;
package/dist/score.js CHANGED
@@ -488,22 +488,38 @@ function scoreBotAccessControl(signals) {
488
488
  let pts = 0;
489
489
  const notes = [];
490
490
  const robots = signals.signals.robots_analysis;
491
- if (robots) {
492
- if (robots.address_count > 0 && !robots.blanket_disallow) {
493
- pts += 10;
494
- notes.push('Per-bot allow/deny posture (no blanket disallow)');
495
- }
496
- else if (robots.address_count > 0) {
497
- pts += 5;
498
- notes.push('Addresses AI agents but uses blanket disallow');
499
- }
500
- if (robots.address_count >= 3) {
501
- pts += 5;
502
- notes.push(`Distinct posture for ${robots.address_count} bots — granular control`);
503
- }
491
+ if (!robots) {
492
+ notes.push('No robots.txt analysis available');
493
+ return { pts: 0, max, status: statusFor(0, max), notes };
494
+ }
495
+ // 10 pts: Cloudflare Content-Signal directive OR equivalent AI-policy declaration.
496
+ // Content-Signal is the modern machine-readable convention; per-bot rules are the
497
+ // older convention and earn partial credit when Content-Signal is absent.
498
+ const cs = robots.content_signal_directives;
499
+ if (cs && Object.keys(cs).length > 0) {
500
+ pts += 10;
501
+ const fmt = Object.entries(cs)
502
+ .map(([k, v]) => `${k}=${v}`)
503
+ .join(', ');
504
+ notes.push(`Content-Signal directive declared: ${fmt}`);
505
+ }
506
+ else if (robots.address_count >= 3) {
507
+ pts += 5;
508
+ notes.push(`AI policy implicit via ${robots.address_count} per-bot rules — consider adding a Content-Signal directive for machine-readable, future-proof AI policy`);
504
509
  }
505
510
  else {
506
- notes.push('No robots.txt analysis available');
511
+ notes.push('No Content-Signal directive and no per-bot AI policy in robots.txt');
512
+ }
513
+ // 5 pts: per-bot granular posture (names ≥3 AI bots and is not paired with a global blanket disallow).
514
+ if (robots.address_count >= 3 && !robots.blanket_disallow) {
515
+ pts += 5;
516
+ notes.push(`Per-bot granular posture for ${robots.address_count} named bots`);
517
+ }
518
+ else if (robots.address_count >= 3 && robots.blanket_disallow) {
519
+ notes.push(`Names ${robots.address_count} bots but pairs with a global blanket disallow`);
520
+ }
521
+ else if (robots.address_count > 0) {
522
+ notes.push(`Names ${robots.address_count} bot(s) — under threshold (need 3+) for granular-control credit`);
507
523
  }
508
524
  return { pts: Math.min(pts, max), max, status: statusFor(pts, max), notes };
509
525
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capitalthought/agentsfirst-mcp",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "MCP server that scores websites and codebases against the Agents First framework. Use it to check how agent-ready any product is. https://agentsfirst.dev",
5
5
  "license": "MIT",
6
6
  "author": "Joshua Baer <josh@capitalfactory.com>",