@myspec/mcp-server 0.1.0-next.8 → 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.
Files changed (2) hide show
  1. package/dist/index.js +28 -21
  2. package/package.json +4 -1
package/dist/index.js CHANGED
@@ -1086,6 +1086,7 @@ function transformSpecSessionResponse(raw) {
1086
1086
  messageCount: raw.message_count,
1087
1087
  tokenCount: raw.token_count,
1088
1088
  context: raw.context,
1089
+ chatHistory: raw.chat_history,
1089
1090
  startedAt: new Date(raw.started_at),
1090
1091
  completedAt: raw.completed_at ? new Date(raw.completed_at) : void 0,
1091
1092
  archivedAt: raw.archived_at ? new Date(raw.archived_at) : void 0,
@@ -1322,6 +1323,17 @@ var HttpFileClient = class {
1322
1323
  expiresAt: new Date(response.expires_at)
1323
1324
  };
1324
1325
  }
1326
+ async getRevisionDownloadUrl(fileId, revisionNumber, jwtToken) {
1327
+ const response = await this.httpClient.get(
1328
+ `/project/v1/files/${fileId}/revisions/${revisionNumber}`,
1329
+ jwtToken,
1330
+ { headers: { Accept: "application/json" } }
1331
+ );
1332
+ return {
1333
+ signedUrl: response.signed_url,
1334
+ expiresAt: new Date(response.expires_at)
1335
+ };
1336
+ }
1325
1337
  async downloadContent(fileId, jwtToken) {
1326
1338
  const baseUrl = this.httpClient.getBaseUrl().replace(/\/$/, "");
1327
1339
  const url = `${baseUrl}/project/v1/files/${fileId}`;
@@ -1519,6 +1531,7 @@ var HttpSpecSessionClient = class {
1519
1531
  if (updates.messageCount !== void 0) body.message_count = updates.messageCount;
1520
1532
  if (updates.tokenCount !== void 0) body.token_count = updates.tokenCount;
1521
1533
  if (updates.context !== void 0) body.context = updates.context;
1534
+ if (updates.chatHistory !== void 0) body.chat_history = updates.chatHistory;
1522
1535
  const raw = await this.httpClient.put(
1523
1536
  `/project/v1/sessions/${sessionId}`,
1524
1537
  body,
@@ -1615,6 +1628,11 @@ var PlatformClient = class {
1615
1628
  async getFileDownloadUrl(fileId) {
1616
1629
  return this.withTokenRetry((jwt) => this.file.getDownloadUrl(fileId, jwt));
1617
1630
  }
1631
+ async getRevisionDownloadUrl(fileId, revisionNumber) {
1632
+ return this.withTokenRetry(
1633
+ (jwt) => this.file.getRevisionDownloadUrl(fileId, revisionNumber, jwt)
1634
+ );
1635
+ }
1618
1636
  async getAttachmentDownloadUrl(attachmentId) {
1619
1637
  return this.withTokenRetry((jwt) => this.attachment.getDownloadUrl(attachmentId, jwt));
1620
1638
  }
@@ -1769,12 +1787,12 @@ import { z as z2 } from "zod";
1769
1787
  var inputSchema2 = {
1770
1788
  file_id: z2.string().min(1).describe("UUID of the file"),
1771
1789
  include_download_url: z2.number().int().nonnegative().optional().describe(
1772
- "Revision number to include a download URL for. Pass `revision_count` for the latest (signed URL); pass an older revision to get a URL plus `download_headers` carrying a short-lived bearer token. Omit or 0 to skip."
1790
+ "Revision number to include a download URL for. Returns a signed, time-limited URL for that revision (latest or historical) that needs no credentials. Omit or 0 to skip."
1773
1791
  )
1774
1792
  };
1775
1793
  var getFileTool = {
1776
1794
  name: "get_file",
1777
- description: "Get file metadata. With `include_download_url=N`, also returns a download URL for revision N: latest returns a signed URL; older revisions return a URL plus `download_headers` containing a short-lived bearer token (treat as sensitive).",
1795
+ description: "Get file metadata. With `include_download_url=N`, also returns a signed, time-limited download URL for revision N (latest or historical). The URL is self-authenticating, so no credentials are returned.",
1778
1796
  inputSchema: inputSchema2,
1779
1797
  handler: async (args, ctx) => {
1780
1798
  const meta = await ctx.client.getFileMetadata(args.file_id);
@@ -1800,24 +1818,12 @@ var getFileTool = {
1800
1818
  );
1801
1819
  }
1802
1820
  const isLatest = requested === meta.revisionCount;
1803
- let downloadBlock;
1804
- if (isLatest) {
1805
- const signed = await ctx.client.getFileDownloadUrl(meta.id);
1806
- downloadBlock = {
1807
- download_url: signed.signedUrl,
1808
- download_revision: meta.revisionCount,
1809
- expires_at: signed.expiresAt.toISOString()
1810
- };
1811
- } else {
1812
- const url = `${ctx.client.baseUrl}/project/v1/files/${encodeURIComponent(meta.id)}/revisions/${String(requested)}`;
1813
- const token = await ctx.client.getAccessTokenWithExpiry();
1814
- downloadBlock = {
1815
- download_url: url,
1816
- download_revision: requested,
1817
- expires_at: new Date(token.expiresAt).toISOString(),
1818
- download_headers: [`Authorization: Bearer ${token.accessToken}`]
1819
- };
1820
- }
1821
+ const signed = isLatest ? await ctx.client.getFileDownloadUrl(meta.id) : await ctx.client.getRevisionDownloadUrl(meta.id, requested);
1822
+ const downloadBlock = {
1823
+ download_url: signed.signedUrl,
1824
+ download_revision: requested,
1825
+ expires_at: signed.expiresAt.toISOString()
1826
+ };
1821
1827
  return jsonResult({ ...base, ...downloadBlock });
1822
1828
  }
1823
1829
  };
@@ -3377,7 +3383,8 @@ async function runOneConnection(opts) {
3377
3383
  headers: {
3378
3384
  Authorization: `Bearer ${opts.accessToken}`,
3379
3385
  "X-Mcp-Client": `myspec-mcp-server/${opts.version}`,
3380
- "X-Mcp-Root-Label": opts.rootLabel
3386
+ "X-Mcp-Root-Label": opts.rootLabel,
3387
+ "X-Client-Type": "mcp-server"
3381
3388
  }
3382
3389
  });
3383
3390
  await waitForOpen(ws);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myspec/mcp-server",
3
- "version": "0.1.0-next.8",
3
+ "version": "0.1.0",
4
4
  "description": "MySpec MCP server — exposes MySpec platform projects, files and attachments to MCP-aware clients via OAuth-authenticated access tokens.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -23,6 +23,8 @@
23
23
  "typecheck": "tsc --noEmit",
24
24
  "test": "vitest run",
25
25
  "test:watch": "vitest",
26
+ "test:coverage": "vitest run --coverage",
27
+ "coverage:check": "npx tsx scripts/check-coverage.ts",
26
28
  "test:integration": "npm run build && vitest run --config vitest.integration.config.ts",
27
29
  "lint": "eslint src",
28
30
  "lint:fix": "eslint src --fix",
@@ -52,6 +54,7 @@
52
54
  "@myspec/shared": "file:../../packages/shared",
53
55
  "@types/node": "^25.9.1",
54
56
  "@types/ws": "^8.18.1",
57
+ "@vitest/coverage-v8": "^3.0.0",
55
58
  "eslint": "^10.4.1",
56
59
  "tsup": "^8.3.5",
57
60
  "tsx": "^4.22.3",