skybridge 2.0.0-beta.3a8ddf2 → 2.0.0-beta.3b39c79

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.
@@ -26,7 +26,9 @@ function registeredResourceNames(server) {
26
26
  describe("skills server option", () => {
27
27
  it("declares the extension capability and registers skill resources from the primed manifest", () => {
28
28
  __setSkillsManifest(MANIFEST);
29
- const server = new McpServer({ name: "t", version: "0.0.1" }, undefined, { skills: true });
29
+ const server = new McpServer({ name: "t", version: "0.0.1" }, undefined, {
30
+ skills: true,
31
+ });
30
32
  expect(extensionsOf(server)?.["io.modelcontextprotocol/skills"]).toEqual({
31
33
  directoryRead: true,
32
34
  });
@@ -36,7 +38,7 @@ describe("skills server option", () => {
36
38
  });
37
39
  it("does nothing when the skills option is absent", () => {
38
40
  __setSkillsManifest(MANIFEST);
39
- const server = new McpServer({ name: "t", version: "0.0.1" }, {});
41
+ const server = new McpServer({ name: "t", version: "0.0.1" });
40
42
  expect(extensionsOf(server)?.["io.modelcontextprotocol/skills"]).toBeUndefined();
41
43
  expect(registeredResourceNames(server)).not.toContain("skill://demo/SKILL.md");
42
44
  });
@@ -76,7 +78,7 @@ describe("skills server option", () => {
76
78
  it("warns when skills are enabled but none are found", () => {
77
79
  __setSkillsManifest([]);
78
80
  const warn = vi.spyOn(console, "warn").mockImplementation(() => { });
79
- new McpServer({ name: "t", version: "0.0.1" }, {}, { skills: true });
81
+ new McpServer({ name: "t", version: "0.0.1" }, undefined, { skills: true });
80
82
  expect(warn).toHaveBeenCalledWith(expect.stringContaining("no skills were found"));
81
83
  warn.mockRestore();
82
84
  });
@@ -1 +1 @@
1
- {"version":3,"file":"skills-integration.test.js","sourceRoot":"","sources":["../../src/server/skills-integration.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { Client, InMemoryTransport } from \"@modelcontextprotocol/client\";\nimport { describe, expect, it, vi } from \"vitest\";\nimport { z } from \"zod\";\nimport {\n __setSkillsManifest,\n McpServer,\n type SkillsManifest,\n Skybridge,\n} from \"./index.js\";\n\nconst MANIFEST: SkillsManifest = [\n {\n uri: \"skill://demo/SKILL.md\",\n frontmatter: { name: \"demo\", description: \"A demo skill\" },\n resources: [\n {\n uri: \"skill://demo/SKILL.md\",\n digest: `sha256:${createHash(\"sha256\").update(\"# Demo\", \"utf8\").digest(\"hex\")}`,\n content: \"# Demo\",\n },\n ],\n },\n];\n\nfunction extensionsOf(server: McpServer): Record<string, unknown> | undefined {\n return (\n server.server as unknown as {\n _capabilities?: { extensions?: Record<string, unknown> };\n }\n )._capabilities?.extensions;\n}\n\nfunction registeredResourceNames(server: McpServer): string[] {\n const registered = (\n server as unknown as {\n _registeredResources?: Record<string, unknown>;\n _registeredResourceTemplates?: Record<string, unknown>;\n }\n )._registeredResources;\n return registered ? Object.keys(registered) : [];\n}\n\ndescribe(\"skills server option\", () => {\n it(\"declares the extension capability and registers skill resources from the primed manifest\", () => {\n __setSkillsManifest(MANIFEST);\n const server = new McpServer(\n { name: \"t\", version: \"0.0.1\" },\n undefined,\n { skills: true },\n );\n\n expect(extensionsOf(server)?.[\"io.modelcontextprotocol/skills\"]).toEqual({\n directoryRead: true,\n });\n // Resources are keyed by URI. Locks that the primed manifest was\n // consumed and wired up.\n expect(registeredResourceNames(server)).toEqual(\n expect.arrayContaining([\"skill://demo/SKILL.md\"]),\n );\n });\n\n it(\"does nothing when the skills option is absent\", () => {\n __setSkillsManifest(MANIFEST);\n const server = new McpServer({ name: \"t\", version: \"0.0.1\" }, {});\n\n expect(\n extensionsOf(server)?.[\"io.modelcontextprotocol/skills\"],\n ).toBeUndefined();\n expect(registeredResourceNames(server)).not.toContain(\n \"skill://demo/SKILL.md\",\n );\n });\n\n it(\"serves skills through the stateless transport (capability + reads)\", async () => {\n __setSkillsManifest(MANIFEST);\n const app = new Skybridge({\n name: \"t\",\n version: \"0.0.1\",\n skills: true,\n handler: (server) => server,\n });\n const client = new Client({ name: \"c\", version: \"0.0.1\" });\n const [clientTransport, serverTransport] =\n InMemoryTransport.createLinkedPair();\n // The production HTTP path builds a fresh per-request server; exercise it\n // directly to lock that skills (capability + resource reads) survive that\n // hop.\n const instance = await app.createServerInstance();\n await instance.connect(serverTransport);\n await client.connect(clientTransport);\n\n expect(\n client.getServerCapabilities()?.extensions?.[\n \"io.modelcontextprotocol/skills\"\n ],\n ).toEqual({ directoryRead: true });\n\n const skill = await client.readResource({ uri: \"skill://demo/SKILL.md\" });\n expect((skill.contents[0] as { text?: string }).text).toBe(\"# Demo\");\n\n const SkillEntrySchema = z.object({\n uri: z.string(),\n frontmatter: z.record(z.string(), z.unknown()),\n resources: z.array(z.object({ uri: z.string(), digest: z.string() })),\n });\n\n const list = await client.request(\n { method: \"skills/list\", params: {} },\n z.object({ skills: z.array(SkillEntrySchema) }),\n );\n expect(list.skills).toHaveLength(1);\n expect(list.skills[0]?.uri).toBe(\"skill://demo/SKILL.md\");\n expect(list.skills[0]?.resources[0]?.digest).toMatch(\n /^sha256:[a-f0-9]{64}$/,\n );\n\n const got = await client.request(\n { method: \"skills/get\", params: { uri: \"skill://demo/SKILL.md\" } },\n z.object({ skill: SkillEntrySchema }),\n );\n expect(got.skill).toEqual(list.skills[0]);\n\n await client.close();\n await instance.close();\n });\n\n it(\"warns when skills are enabled but none are found\", () => {\n __setSkillsManifest([]);\n const warn = vi.spyOn(console, \"warn\").mockImplementation(() => {});\n new McpServer({ name: \"t\", version: \"0.0.1\" }, {}, { skills: true });\n expect(warn).toHaveBeenCalledWith(\n expect.stringContaining(\"no skills were found\"),\n );\n warn.mockRestore();\n });\n});\n"]}
1
+ {"version":3,"file":"skills-integration.test.js","sourceRoot":"","sources":["../../src/server/skills-integration.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { Client, InMemoryTransport } from \"@modelcontextprotocol/client\";\nimport { describe, expect, it, vi } from \"vitest\";\nimport { z } from \"zod\";\nimport {\n __setSkillsManifest,\n McpServer,\n type SkillsManifest,\n Skybridge,\n} from \"./index.js\";\n\nconst MANIFEST: SkillsManifest = [\n {\n uri: \"skill://demo/SKILL.md\",\n frontmatter: { name: \"demo\", description: \"A demo skill\" },\n resources: [\n {\n uri: \"skill://demo/SKILL.md\",\n digest: `sha256:${createHash(\"sha256\").update(\"# Demo\", \"utf8\").digest(\"hex\")}`,\n content: \"# Demo\",\n },\n ],\n },\n];\n\nfunction extensionsOf(server: McpServer): Record<string, unknown> | undefined {\n return (\n server.server as unknown as {\n _capabilities?: { extensions?: Record<string, unknown> };\n }\n )._capabilities?.extensions;\n}\n\nfunction registeredResourceNames(server: McpServer): string[] {\n const registered = (\n server as unknown as {\n _registeredResources?: Record<string, unknown>;\n _registeredResourceTemplates?: Record<string, unknown>;\n }\n )._registeredResources;\n return registered ? Object.keys(registered) : [];\n}\n\ndescribe(\"skills server option\", () => {\n it(\"declares the extension capability and registers skill resources from the primed manifest\", () => {\n __setSkillsManifest(MANIFEST);\n const server = new McpServer({ name: \"t\", version: \"0.0.1\" }, undefined, {\n skills: true,\n });\n\n expect(extensionsOf(server)?.[\"io.modelcontextprotocol/skills\"]).toEqual({\n directoryRead: true,\n });\n // Resources are keyed by URI. Locks that the primed manifest was\n // consumed and wired up.\n expect(registeredResourceNames(server)).toEqual(\n expect.arrayContaining([\"skill://demo/SKILL.md\"]),\n );\n });\n\n it(\"does nothing when the skills option is absent\", () => {\n __setSkillsManifest(MANIFEST);\n const server = new McpServer({ name: \"t\", version: \"0.0.1\" });\n\n expect(\n extensionsOf(server)?.[\"io.modelcontextprotocol/skills\"],\n ).toBeUndefined();\n expect(registeredResourceNames(server)).not.toContain(\n \"skill://demo/SKILL.md\",\n );\n });\n\n it(\"serves skills through the stateless transport (capability + reads)\", async () => {\n __setSkillsManifest(MANIFEST);\n const app = new Skybridge({\n name: \"t\",\n version: \"0.0.1\",\n skills: true,\n handler: (server) => server,\n });\n const client = new Client({ name: \"c\", version: \"0.0.1\" });\n const [clientTransport, serverTransport] =\n InMemoryTransport.createLinkedPair();\n // The production HTTP path builds a fresh per-request server; exercise it\n // directly to lock that skills (capability + resource reads) survive that\n // hop.\n const instance = await app.createServerInstance();\n await instance.connect(serverTransport);\n await client.connect(clientTransport);\n\n expect(\n client.getServerCapabilities()?.extensions?.[\n \"io.modelcontextprotocol/skills\"\n ],\n ).toEqual({ directoryRead: true });\n\n const skill = await client.readResource({ uri: \"skill://demo/SKILL.md\" });\n expect((skill.contents[0] as { text?: string }).text).toBe(\"# Demo\");\n\n const SkillEntrySchema = z.object({\n uri: z.string(),\n frontmatter: z.record(z.string(), z.unknown()),\n resources: z.array(z.object({ uri: z.string(), digest: z.string() })),\n });\n\n const list = await client.request(\n { method: \"skills/list\", params: {} },\n z.object({ skills: z.array(SkillEntrySchema) }),\n );\n expect(list.skills).toHaveLength(1);\n expect(list.skills[0]?.uri).toBe(\"skill://demo/SKILL.md\");\n expect(list.skills[0]?.resources[0]?.digest).toMatch(\n /^sha256:[a-f0-9]{64}$/,\n );\n\n const got = await client.request(\n { method: \"skills/get\", params: { uri: \"skill://demo/SKILL.md\" } },\n z.object({ skill: SkillEntrySchema }),\n );\n expect(got.skill).toEqual(list.skills[0]);\n\n await client.close();\n await instance.close();\n });\n\n it(\"warns when skills are enabled but none are found\", () => {\n __setSkillsManifest([]);\n const warn = vi.spyOn(console, \"warn\").mockImplementation(() => {});\n new McpServer({ name: \"t\", version: \"0.0.1\" }, undefined, { skills: true });\n expect(warn).toHaveBeenCalledWith(\n expect.stringContaining(\"no skills were found\"),\n );\n warn.mockRestore();\n });\n});\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skybridge",
3
- "version": "2.0.0-beta.3a8ddf2",
3
+ "version": "2.0.0-beta.3b39c79",
4
4
  "description": "Skybridge is a framework for building ChatGPT and MCP Apps",
5
5
  "repository": {
6
6
  "type": "git",