@unfragile/mcp-server 0.3.2 → 0.4.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.
Files changed (3) hide show
  1. package/README.md +12 -0
  2. package/dist/index.js +121 -11
  3. package/package.json +5 -3
package/README.md CHANGED
@@ -59,6 +59,8 @@ Add to `~/.codeium/windsurf/mcp_config.json`:
59
59
 
60
60
  ## Tools
61
61
 
62
+ ### Discovery and trust (human-readable)
63
+
62
64
  | Tool | Description |
63
65
  |------|-------------|
64
66
  | `search` | Find AI tools by intent. "best framework for building AI agents" |
@@ -72,6 +74,16 @@ Add to `~/.codeium/windsurf/mcp_config.json`:
72
74
  | `subscribe` | Watch for new artifacts matching a capability need |
73
75
  | `unsubscribe` | Cancel a monitor |
74
76
 
77
+ ### Capability Protocol v1 (raw JSON, machine-readable)
78
+
79
+ | Tool | Description |
80
+ |------|-------------|
81
+ | `unfragile_validate` | Validate an `unfragile.yml` manifest against the Capability Protocol v1 schema. Returns errors, warnings, and the parsed manifest. |
82
+ | `unfragile_passport` | Fetch the raw `trust_passport_v1` JSON for an artifact by slug. Suitable for programmatic policy checks. |
83
+ | `unfragile_resolve_capability` | Resolve a `capability://` URI or natural-language intent into ranked artifacts as raw JSON. Optional inline passports for one-call decisioning. |
84
+
85
+ Learn more about the protocol: <https://unfragile.ai/protocol>.
86
+
75
87
  ## Examples
76
88
 
77
89
  Once installed, ask your agent:
package/dist/index.js CHANGED
@@ -7,16 +7,21 @@
7
7
  // the graph learns from every interaction.
8
8
  //
9
9
  // Tools:
10
- // search — Find AI tools by intent/query (with Match Proof)
11
- // find_mcps — Discover MCP servers by capability need
12
- // get_artifact — Get full details + capabilities for an artifact
13
- // resolve_capability — Resolve capability:// URIs to trusted artifacts
14
- // trust_passport — Get machine-readable trust passport for an artifact
15
- // compare — Compare two artifacts side-by-side
16
- // find_stack — Assemble a complete harness stack for a use case
17
- // feedback — Report success/failure to close the learning loop
18
- // subscribe — Set up persistent watch for new tools
19
- // unsubscribe — Cancel a persistent watch
10
+ // search — Find AI tools by intent/query (with Match Proof)
11
+ // find_mcps — Discover MCP servers by capability need
12
+ // get_artifact — Get full details + capabilities for an artifact
13
+ // resolve_capability — Resolve capability:// URIs to trusted artifacts (formatted)
14
+ // trust_passport — Get machine-readable trust passport for an artifact (formatted)
15
+ // compare — Compare two artifacts side-by-side
16
+ // find_stack — Assemble a complete harness stack for a use case
17
+ // feedback — Report success/failure to close the learning loop
18
+ // subscribe — Set up persistent watch for new tools
19
+ // unsubscribe — Cancel a persistent watch
20
+ //
21
+ // Protocol-native (raw JSON, Unfragile Capability Protocol v1):
22
+ // unfragile_validate — Validate an unfragile.yml manifest
23
+ // unfragile_passport — Raw trust passport JSON for an artifact
24
+ // unfragile_resolve_capability — Raw resolver JSON for a capability:// URI / intent
20
25
  // ─────────────────────────────────────────────────────────────
21
26
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
22
27
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
@@ -257,7 +262,7 @@ function formatResolve(data) {
257
262
  // ─── MCP Server ──────────────────────────────────────────────
258
263
  const server = new McpServer({
259
264
  name: "unfragile",
260
- version: "0.3.0",
265
+ version: "0.4.0",
261
266
  });
262
267
  // Tool 1: General search
263
268
  server.tool("search", "Search the Unfragile match graph for AI tools, frameworks, APIs, MCP servers, agents, and more. Returns ranked results with capability matches and graph signals. Every query feeds the graph.", {
@@ -598,6 +603,111 @@ server.tool("subscribe", "Set up a persistent watch for new AI tools matching a
598
603
  };
599
604
  }
600
605
  });
606
+ // ─── Protocol-native tools ──────────────────────────────────
607
+ //
608
+ // These three tools mirror the Unfragile Capability Protocol
609
+ // endpoints 1:1 and return raw JSON. Use them when you want
610
+ // machine-readable output rather than the formatted markdown
611
+ // returned by `trust_passport` / `resolve_capability`.
612
+ async function validateManifestAPI(body) {
613
+ const headers = {
614
+ "Content-Type": "application/json",
615
+ Accept: "application/json",
616
+ };
617
+ if (API_KEY)
618
+ headers["X-API-Key"] = API_KEY;
619
+ const controller = new AbortController();
620
+ const timeout = setTimeout(() => controller.abort(), 15_000);
621
+ try {
622
+ const res = await fetch(`${API_BASE}/api/v1/validate`, {
623
+ method: "POST",
624
+ headers,
625
+ body: JSON.stringify(body),
626
+ signal: controller.signal,
627
+ });
628
+ const text = await res.text();
629
+ try {
630
+ return JSON.parse(text);
631
+ }
632
+ catch {
633
+ throw new Error(`Validator returned non-JSON (${res.status}): ${text.slice(0, 300)}`);
634
+ }
635
+ }
636
+ finally {
637
+ clearTimeout(timeout);
638
+ }
639
+ }
640
+ // Tool: unfragile_validate
641
+ server.tool("unfragile_validate", "Validate an unfragile.yml manifest against the Unfragile Capability Protocol v1. Returns the structured validation result with errors, warnings, and the parsed manifest. Use this before submitting an artifact or in CI pipelines. Accepts raw YAML text via `yaml_content`.", {
642
+ yaml_content: z
643
+ .string()
644
+ .min(10)
645
+ .max(200_000)
646
+ .describe("Raw contents of the unfragile.yml file"),
647
+ }, async ({ yaml_content }) => {
648
+ log("unfragile_validate", `${yaml_content.length} bytes`);
649
+ try {
650
+ const data = await validateManifestAPI({ yaml: yaml_content });
651
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
652
+ }
653
+ catch (err) {
654
+ return {
655
+ content: [
656
+ { type: "text", text: `Error validating manifest: ${err instanceof Error ? err.message : String(err)}` },
657
+ ],
658
+ isError: true,
659
+ };
660
+ }
661
+ });
662
+ // Tool: unfragile_passport — raw JSON trust passport
663
+ server.tool("unfragile_passport", "Fetch the raw machine-readable trust passport for an artifact by slug (trust_passport_v1 schema). Returns JSON suitable for programmatic policy checks. Pair with `trust_passport` when you want a human-readable summary.", {
664
+ slug: z.string().min(1).max(200).describe("Artifact slug (e.g., 'cursor', 'langchain', 'postgres-mcp-server')"),
665
+ }, async ({ slug }) => {
666
+ log("unfragile_passport", slug);
667
+ try {
668
+ const data = await passportAPI(slug);
669
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
670
+ }
671
+ catch (err) {
672
+ return {
673
+ content: [
674
+ { type: "text", text: `Error fetching passport: ${err instanceof Error ? err.message : String(err)}` },
675
+ ],
676
+ isError: true,
677
+ };
678
+ }
679
+ });
680
+ // Tool: unfragile_resolve_capability — raw JSON resolver
681
+ server.tool("unfragile_resolve_capability", "Resolve a `capability://` URI or a natural-language capability into ranked artifacts, with trust signals and passport URLs. Returns raw JSON so an agent can make a programmatic selection. Pair with `resolve_capability` when you want a human-readable summary.", {
682
+ uri_or_intent: z
683
+ .string()
684
+ .min(2)
685
+ .max(500)
686
+ .describe("Capability URI like `capability://database.postgres.query.readonly`, or a natural-language capability description"),
687
+ limit: z.number().min(1).max(20).default(5).describe("Max resolutions"),
688
+ risk: z
689
+ .enum(["default", "production", "enterprise", "strict"])
690
+ .default("default")
691
+ .describe("Risk posture — stricter modes require stronger quality/status gates"),
692
+ passport: z
693
+ .boolean()
694
+ .default(false)
695
+ .describe("Inline the full trust passport for each resolution (larger response)"),
696
+ }, async ({ uri_or_intent, limit, risk, passport }) => {
697
+ log("unfragile_resolve_capability", uri_or_intent);
698
+ try {
699
+ const data = await resolveAPI(uri_or_intent, { limit, risk, passport });
700
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
701
+ }
702
+ catch (err) {
703
+ return {
704
+ content: [
705
+ { type: "text", text: `Error resolving capability: ${err instanceof Error ? err.message : String(err)}` },
706
+ ],
707
+ isError: true,
708
+ };
709
+ }
710
+ });
601
711
  // Tool 10: Unsubscribe — delete a monitor
602
712
  server.tool("unsubscribe", "Cancel a persistent watch (monitor). Use the monitor ID returned from subscribe.", {
603
713
  monitorId: z.string().min(1).describe("Monitor ID from subscribe (e.g., 'mon_...')"),
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@unfragile/mcp-server",
3
- "version": "0.3.2",
3
+ "version": "0.4.0",
4
4
  "mcpName": "io.github.Savirinc/unfragile",
5
- "description": "Unfragile MCP Server — agent-native discovery, trust, and routing for AI artifacts.",
5
+ "description": "Unfragile MCP Server — agent-native discovery, trust, and routing for AI artifacts. Implements the Unfragile Capability Protocol v1.",
6
6
  "keywords": [
7
7
  "mcp",
8
8
  "ai",
@@ -12,7 +12,9 @@
12
12
  "routing",
13
13
  "capabilities",
14
14
  "unfragile",
15
- "harness-engineering"
15
+ "harness-engineering",
16
+ "capability-protocol",
17
+ "unfragile.yml"
16
18
  ],
17
19
  "license": "MIT",
18
20
  "author": "Unfragile <hello@unfragile.ai>",