@capitalthought/agentsfirst-mcp 0.1.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/dist/server.js ADDED
@@ -0,0 +1,153 @@
1
+ #!/usr/bin/env node
2
+ // agentsfirst-mcp — MCP server that scores any product against the Agents First framework.
3
+ //
4
+ // Interface First applied to itself: 5 verb-first tools, Zod-typed params, structured returns.
5
+ // Read AGENTS.md for the rules on how to call these tools — permissions, sequence, errors.
6
+ //
7
+ // See https://agentsfirst.dev/principles/
8
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
9
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
10
+ import { z } from 'zod';
11
+ import { runPrep } from './prep.js';
12
+ import { probeCodebase, probeWebsite } from './probe.js';
13
+ import { scoreCodebase, scoreWebsite } from './score.js';
14
+ import { ANTI_PATTERNS, ANTI_PATTERN_SLUGS, PRINCIPLES, PRINCIPLE_SLUGS, } from './principles.js';
15
+ const VERSION = '0.1.0';
16
+ const TOOL_COUNT = 5;
17
+ const server = new McpServer({
18
+ name: 'agentsfirst-mcp',
19
+ version: VERSION,
20
+ });
21
+ const AGENTS_MD_REF = 'See AGENTS.md (https://agentsfirst.dev/principles/contract-first/) for permissions, sequence, and error contract.';
22
+ function jsonContent(payload, isError = false) {
23
+ return {
24
+ content: [
25
+ {
26
+ type: 'text',
27
+ text: JSON.stringify(payload, null, 2),
28
+ },
29
+ ],
30
+ isError,
31
+ };
32
+ }
33
+ // ─── agentsfirst_prep ─────────────────────────────────────────────────────────
34
+ server.registerTool('agentsfirst_prep', {
35
+ title: 'Prep gate — verify rubric loaded, network reachable',
36
+ description: `Prep Gate for agentsfirst-mcp. Call this first, every session, before any other tool. Returns ok=true when the rubric is loaded, node>=20, and the canonical principles URL is reachable. ${AGENTS_MD_REF}`,
37
+ inputSchema: {},
38
+ }, async () => {
39
+ const result = await runPrep();
40
+ return jsonContent(result, !result.ok);
41
+ });
42
+ // ─── score_codebase ───────────────────────────────────────────────────────────
43
+ server.registerTool('score_codebase', {
44
+ title: 'Score a local directory against the 8 principles',
45
+ description: `Probes a local codebase and scores it against the Agents First rubric (100 pts). Returns score, level (0–4), per-principle breakdown, anti-pattern flags, and ranked top moves. Read-only — never writes anywhere. ${AGENTS_MD_REF}`,
46
+ inputSchema: {
47
+ path: z
48
+ .string()
49
+ .default(process.cwd())
50
+ .describe('Absolute or relative path to the directory to score. Defaults to cwd.'),
51
+ depth: z
52
+ .enum(['quick', 'standard', 'deep'])
53
+ .default('standard')
54
+ .describe('Probe depth. quick = signals only, standard = signals + scoring, deep = standard + extra heuristics. Currently all three behave the same; param reserved for future heuristics.'),
55
+ },
56
+ }, async ({ path: targetPath }) => {
57
+ try {
58
+ const signals = await probeCodebase(targetPath);
59
+ const score = scoreCodebase(signals);
60
+ return jsonContent(score);
61
+ }
62
+ catch (err) {
63
+ return jsonContent({
64
+ error: 'probe_failed',
65
+ suggestion: 'verify the path exists and is a directory; absolute paths preferred',
66
+ detail: err.message,
67
+ }, true);
68
+ }
69
+ });
70
+ // ─── score_website ────────────────────────────────────────────────────────────
71
+ server.registerTool('score_website', {
72
+ title: 'Score a public website against agent-readiness dimensions',
73
+ description: `HTTP-probes a URL for agent-discoverable surfaces (robots.txt, /llms.txt, /AGENTS.md, /.well-known/*, OpenAPI, MCP server card, markdown content negotiation) and scores against 5 dimensions (100 pts). Returns score, level, dimensions, anti-pattern flags, top moves. Read-only. ${AGENTS_MD_REF}`,
74
+ inputSchema: {
75
+ url: z
76
+ .string()
77
+ .url()
78
+ .refine((u) => /^https?:\/\//i.test(u), { message: 'must be http or https' })
79
+ .describe('Public URL to probe. Must be http:// or https://.'),
80
+ },
81
+ }, async ({ url }) => {
82
+ try {
83
+ const signals = await probeWebsite(url);
84
+ const score = scoreWebsite(signals);
85
+ return jsonContent(score);
86
+ }
87
+ catch (err) {
88
+ return jsonContent({
89
+ error: 'probe_failed',
90
+ suggestion: 'verify the URL is reachable and starts with http:// or https://',
91
+ detail: err.message,
92
+ }, true);
93
+ }
94
+ });
95
+ // ─── get_principle ────────────────────────────────────────────────────────────
96
+ server.registerTool('get_principle', {
97
+ title: 'Get the canonical text of one Agents First principle',
98
+ description: `Returns the canonical name, summary (~60 words), full URL on agentsfirst.dev, and the anti-patterns this principle defends against. Use after score_* to give the consumer agent context for what to fix. ${AGENTS_MD_REF}`,
99
+ inputSchema: {
100
+ slug: z
101
+ .enum([
102
+ 'interface-first',
103
+ 'contract-first',
104
+ 'prep-gates',
105
+ 'typed-state',
106
+ 'visible-outputs',
107
+ 'multi-model-verification',
108
+ 'perspective-dispatch',
109
+ 'autonomous-recovery',
110
+ ])
111
+ .describe('Principle slug. One of: interface-first, contract-first, prep-gates, typed-state, visible-outputs, multi-model-verification, perspective-dispatch, autonomous-recovery.'),
112
+ },
113
+ }, async ({ slug }) => {
114
+ const p = PRINCIPLES[slug];
115
+ if (!p) {
116
+ return jsonContent({
117
+ error: 'not_found',
118
+ suggestion: `valid slugs: ${PRINCIPLE_SLUGS.join(', ')}`,
119
+ }, true);
120
+ }
121
+ return jsonContent(p);
122
+ });
123
+ // ─── get_anti_pattern ─────────────────────────────────────────────────────────
124
+ server.registerTool('get_anti_pattern', {
125
+ title: 'Get the canonical definition of one Agents First anti-pattern',
126
+ description: `Returns the canonical name, definition, the principle it opposes, and the glossary URL. Use after score_* to explain why a flagged anti-pattern matters. ${AGENTS_MD_REF}`,
127
+ inputSchema: {
128
+ slug: z
129
+ .enum([
130
+ 'lazy-wrapper',
131
+ 'invisible-product',
132
+ 'agents-without-rules',
133
+ 'single-model-trust',
134
+ 'slow-chatbot',
135
+ 'ship-and-forget',
136
+ 'god-server',
137
+ ])
138
+ .describe('Anti-pattern slug. One of: lazy-wrapper, invisible-product, agents-without-rules, single-model-trust, slow-chatbot, ship-and-forget, god-server.'),
139
+ },
140
+ }, async ({ slug }) => {
141
+ const a = ANTI_PATTERNS[slug];
142
+ if (!a) {
143
+ return jsonContent({
144
+ error: 'not_found',
145
+ suggestion: `valid slugs: ${ANTI_PATTERN_SLUGS.join(', ')}`,
146
+ }, true);
147
+ }
148
+ return jsonContent(a);
149
+ });
150
+ // ─── Boot ─────────────────────────────────────────────────────────────────────
151
+ const transport = new StdioServerTransport();
152
+ await server.connect(transport);
153
+ process.stderr.write(`agentsfirst-mcp v${VERSION} ready · ${TOOL_COUNT} tools · https://agentsfirst.dev\n`);
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@capitalthought/agentsfirst-mcp",
3
+ "version": "0.1.0",
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
+ "license": "MIT",
6
+ "author": "Joshua Baer <josh@capitalfactory.com>",
7
+ "homepage": "https://agentsfirst.dev",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/capitalthought/agentsfirst.git",
11
+ "directory": "tools/agentsfirst-mcp"
12
+ },
13
+ "keywords": [
14
+ "agents-first",
15
+ "mcp",
16
+ "model-context-protocol",
17
+ "agent-readiness",
18
+ "scoring",
19
+ "framework"
20
+ ],
21
+ "type": "module",
22
+ "bin": {
23
+ "agentsfirst-mcp": "dist/server.js"
24
+ },
25
+ "files": [
26
+ "dist/",
27
+ "README.md",
28
+ "LICENSE",
29
+ "AGENTS.md"
30
+ ],
31
+ "scripts": {
32
+ "dev": "tsx watch src/server.ts",
33
+ "build": "tsc -p .",
34
+ "start": "node dist/server.js",
35
+ "prep": "tsx src/prep.ts"
36
+ },
37
+ "dependencies": {
38
+ "@modelcontextprotocol/sdk": "^1.0.0",
39
+ "zod": "^3.23.0"
40
+ },
41
+ "devDependencies": {
42
+ "@types/node": "^20.0.0",
43
+ "tsx": "^4.0.0",
44
+ "typescript": "^5.4.0"
45
+ },
46
+ "engines": {
47
+ "node": ">=20"
48
+ }
49
+ }