{
  "markdown": "# msforms-api\n\nAI-native Microsoft Forms automation for inspecting forms, resolving branching,\nvalidating answers, uploading files, submitting responses, and saving response\nlinks.\n\nUse it as:\n\n1. **MCP server** for AI agents and editors — recommended for most users.\n2. **Agent skill** backed by the CLI for agents that can run shell commands.\n3. **CLI** for scripts and terminal workflows.\n4. **TypeScript SDK** for custom applications.\n\n[<img src=\"https://img.shields.io/badge/VS_Code-Install_Server-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white\" alt=\"Install in VS Code\">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%257B%2522name%2522%253A%2522microsoft-forms%2522%252C%2522command%2522%253A%2522npx%2522%252C%2522args%2522%253A%255B%2522-y%2522%252C%2522-p%2522%252C%2522msforms-api%2540latest%2522%252C%2522msforms-api-mcp%2522%255D%257D)\n[<img src=\"https://img.shields.io/badge/VS_Code_Insiders-Install_Server-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white\" alt=\"Install in VS Code Insiders\">](https://insiders.vscode.dev/redirect?url=vscode-insiders%3Amcp%2Finstall%3F%257B%2522name%2522%253A%2522microsoft-forms%2522%252C%2522command%2522%253A%2522npx%2522%252C%2522args%2522%253A%255B%2522-y%2522%252C%2522-p%2522%252C%2522msforms-api%2540latest%2522%252C%2522msforms-api-mcp%2522%255D%257D)\n[![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=microsoft-forms&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIi1wIiwibXNmb3Jtcy1hcGlAbGF0ZXN0IiwibXNmb3Jtcy1hcGktbWNwIl19)\n[![npm version](https://img.shields.io/npm/v/msforms-api?style=flat-square)](https://www.npmjs.com/package/msforms-api)\n[![CI](https://img.shields.io/github/actions/workflow/status/Maxim-Mazurok/msforms-api/ci.yml?branch=main&style=flat-square&label=CI)](https://github.com/Maxim-Mazurok/msforms-api/actions/workflows/ci.yml)\n\n> [!NOTE]\n> This project was generated by GitHub Copilot App using GPT-5.6 Sol with\n> Extra High reasoning in Autopilot mode.\n\n> [!WARNING]\n> This project uses reverse-engineered Microsoft Forms web APIs. Microsoft does\n> not document or guarantee these endpoints. They can change without notice.\n> This project is not affiliated with or endorsed by Microsoft.\n\n## Quick start\n\n### Prerequisites\n\n- [Node.js](https://nodejs.org/) 22 or later.\n- Google Chrome or Microsoft Edge. Playwright Chromium is installed\n  automatically when neither is available.\n\n### Install as an agent skill\n\nThe [CLI skill](SKILL.md) teaches agents how to inspect branching, prepare and\nvalidate answers, upload authorized files, and require explicit approval before\nsubmission:\n\n```bash\nnpx -y skills add Maxim-Mazurok/msforms-api\n```\n\nThe installer detects supported agents such as Claude Code, Cursor, GitHub\nCopilot, and Codex, then asks where to install the skill. Choose global scope to\nuse it across projects.\n\nThe skill runs `msforms-api` through `npx`, so it does not require a global\npackage installation or MCP configuration. It is an alternative interface to\nthe MCP server; both use the same CLI and SDK behavior.\n\n### Install in an AI tool\n\nClick an install badge above, or use this MCP configuration. For Cursor, save\nit as `~/.cursor/mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"microsoft-forms\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"-p\", \"msforms-api@latest\", \"msforms-api-mcp\"]\n    }\n  }\n}\n```\n\nOn first use, ask your agent to authenticate Microsoft Forms. A browser opens\nfor sign-in, then future operations reuse the persistent session.\n\nTry:\n\n> Inspect this Microsoft Form and explain every question, validation, upload\n> rule, and branch: `https://forms.cloud.microsoft/...`\n\nThe agent can prepare and validate answers without submitting. Submission uses\na separate destructive MCP tool and requires explicit confirmation.\n\n<details>\n<summary><strong>VS Code CLI installation</strong></summary>\n\nmacOS / Linux:\n\n```bash\ncode --add-mcp '{\"name\":\"microsoft-forms\",\"command\":\"npx\",\"args\":[\"-y\",\"-p\",\"msforms-api@latest\",\"msforms-api-mcp\"]}'\n```\n\nWindows PowerShell:\n\n```powershell\ncode --add-mcp '{\"name\":\"microsoft-forms\",\"command\":\"npx\",\"args\":[\"-y\",\"-p\",\"msforms-api@latest\",\"msforms-api-mcp\"]}'\n```\n\n</details>\n\n<details>\n<summary><strong>Claude Desktop</strong></summary>\n\nAdd the MCP configuration above to `claude_desktop_config.json`.\n\n</details>\n\n<details>\n<summary><strong>Claude Code</strong></summary>\n\n```bash\nclaude mcp add microsoft-forms -- npx -y -p msforms-api@latest msforms-api-mcp\n```\n\n</details>\n\n<details>\n<summary><strong>Windsurf and other MCP clients</strong></summary>\n\nAdd the MCP configuration above to your client's MCP configuration file.\n\n</details>\n\n## What agents can do\n\n- Read complete form metadata, including raw API objects.\n- Understand question types, options, required state, and text validation.\n- Resolve choice branching through stable question identifiers.\n- Inspect matrix rows and their shared options.\n- Inspect file count, size, and extension restrictions.\n- Validate and serialize answers without submitting.\n- Upload files through the authenticated Forms frontend.\n- Submit only after explicit confirmation.\n- Save and list response links in the signed-in account.\n\n## MCP tools\n\n| Tool                         | Behavior                                           |\n| ---------------------------- | -------------------------------------------------- |\n| `forms_authenticate`         | Opens visible browser login                        |\n| `forms_inspect`              | Returns normalized and raw form structure          |\n| `forms_validate`             | Resolves branches and validates without submitting |\n| `forms_upload_file`          | Uploads a local file and returns answer metadata   |\n| `forms_submit`               | Creates a response after elicited confirmation     |\n| `forms_save_response`        | Saves an existing response link                    |\n| `forms_list_saved_responses` | Lists saved response links                         |\n\n`forms_submit` is marked destructive and non-idempotent. It uses MCP v2\nmulti-round-trip elicitation. Declined or false confirmation never reaches\nsubmission code.\n\nCross-cutting workflow and safety guidance is also available through:\n\n```bash\nnpx -y -p msforms-api@latest msforms-api guide\n```\n\n## CLI\n\nRun without installing globally:\n\n```bash\n# Sign in once\nnpx -y -p msforms-api@latest msforms-api auth\n\n# Inspect a form\nnpx -y -p msforms-api@latest msforms-api inspect \\\n  --form 'https://forms.cloud.microsoft/Pages/ResponsePage.aspx?id=...'\n\n# Validate answers without submitting\nnpx -y -p msforms-api@latest msforms-api validate \\\n  --form 'https://forms.cloud.microsoft/Pages/ResponsePage.aspx?id=...' \\\n  --answers @answers.json\n\n# Submit only when intended\nnpx -y -p msforms-api@latest msforms-api submit \\\n  --form 'https://forms.cloud.microsoft/Pages/ResponsePage.aspx?id=...' \\\n  --answers @answers.json \\\n  --save-response \\\n  --confirm\n```\n\nFrequent CLI users can install globally:\n\n```bash\nnpm install --global msforms-api\nmsforms-api auth\n```\n\nEvery command emits JSON. Add `--compact` for single-line output.\n\n## Authentication and local data\n\nAuthentication opens a visible browser and stores its profile under:\n\n```text\n~/.msforms-api/browser-profile\n```\n\nThe SDK uses that profile to obtain scoped Forms cookies, an anti-forgery\ntoken, and session metadata. It does not print or return those credentials.\nNormal reads and submissions use direct Forms HTTP requests. File upload is\nbrowser-assisted because the Forms frontend manages SharePoint authorization.\n\nOverride the profile or browser:\n\n```bash\nmsforms-api --profile ~/.config/my-forms-profile --browser chrome auth\n```\n\nMCP environment variables:\n\n| Variable                    | Purpose                                            |\n| --------------------------- | -------------------------------------------------- |\n| `MSFORMS_PROFILE_DIRECTORY` | Persistent browser profile override                |\n| `MSFORMS_BROWSER_CHANNEL`   | `chrome` or `msedge`                               |\n| `MSFORMS_HEADLESS`          | Set to `false` to show operational browser windows |\n\nDelete `~/.msforms-api/browser-profile` to remove the local session.\n\n## Answer format\n\nAnswers are keyed by exact question ID returned from `forms_inspect`.\n\n| Question type   | Input                                             |\n| --------------- | ------------------------------------------------- |\n| Text            | String                                            |\n| Single choice   | Option label or ID                                |\n| Multiple choice | Array of option labels or IDs                     |\n| Date            | `YYYY-MM-DD` string                               |\n| Rating or NPS   | Number                                            |\n| Ranking         | Ordered array containing every option label or ID |\n| Matrix row      | Option label, or `{ \"id\": ..., \"key\": ... }`      |\n| File upload     | Array of objects returned by `forms_upload_file`  |\n\nMatrix answers use each row question ID, not the matrix group ID.\n\n```json\n{\n  \"text-question-id\": \"Ada Lovelace\",\n  \"multiple-choice-question-id\": [\"Desktop\", \"Laptop\"],\n  \"date-question-id\": \"2026-08-12\",\n  \"ranking-question-id\": [\"Branching\", \"Uploads\", \"Ratings\"],\n  \"matrix-row-question-id\": { \"label\": \"Agree\" },\n  \"file-question-id\": [\n    {\n      \"name\": \"document.pdf\",\n      \"uploadSessionUrl\": \"https://...\",\n      \"link\": \"https://...\",\n      \"badgerToken\": null,\n      \"time\": 1786492949627,\n      \"status\": 3,\n      \"id\": \"sharepoint-item-id\"\n    }\n  ]\n}\n```\n\n## SDK\n\n```bash\nnpm install msforms-api\n```\n\n```ts\nimport { MicrosoftFormsClient } from \"msforms-api\";\n\nconst client = new MicrosoftFormsClient();\nconst form = await client.getForm(formUrl);\n\nconst answers = {\n  [form.questions[0].id]: \"Example answer\",\n};\n\nconst validation = await client.validateAnswers(formUrl, answers);\nif (!validation.valid) {\n  throw new Error(JSON.stringify(validation.issues));\n}\n\nconst submission = await client.submitResponse(formUrl, answers, {\n  saveResponse: true,\n});\n\nif (submission.saveResponseStatus === \"failed\") {\n  console.error(submission.saveResponseError);\n  await client.saveResponse(\n    formUrl,\n    submission.responseId,\n    submission.submitDate,\n  );\n}\n```\n\n`submitResponse()` is direct at SDK level. Applications using the SDK must\nimplement their own user confirmation boundary. CLI requires `--confirm`; MCP\nrequires elicitation.\n\n`submissionStatus: \"submitted\"` or a returned `responseId` means the permanent\nresponse exists. A requested response-link save can fail independently. In\nthat case, `saveResponseStatus` is `\"failed\"`, submission details remain in the\nresult, and callers must not submit again. Retry only the idempotent\n`saveResponse()` operation.\n\n## Form structure\n\nThe normalized form model includes:\n\n- IDs, titles, subtitles, order, type, and required state.\n- Choice labels and `branchTargetId` values.\n- Matrix rows with inherited options.\n- Text validation boundaries and rules.\n- File upload restrictions.\n- Parsed form settings.\n- Full raw form and question objects for forward compatibility.\n\nExample branch:\n\n```json\n{\n  \"id\": \"source-question-id\",\n  \"type\": \"Question.Choice\",\n  \"options\": [\n    {\n      \"label\": \"Yes\",\n      \"branchTargetId\": \"target-question-id\"\n    }\n  ]\n}\n```\n\n`forms_validate` returns visible question IDs, issues, and the exact serialized\nanswer array. Questions skipped by branching are omitted.\n\n## How it works\n\nBrowser bootstrap exposes the anti-forgery token, server session ID, form-owner\ntenant and user, responder tenant and user, and form prefetch URL. The client\ncombines that data with scoped Forms cookies for direct requests.\n\nObserved endpoint families:\n\n```text\nGET  /formapi/api/{tenant}/users/{owner}/light/runtimeForms('{formId}')\nPOST /formapi/api/{tenant}/users/{owner}/forms('{formId}')/responses\nPOST /formapi/api/{tenant}/users/{owner}/runtimeForms('{formId}')/questions('{questionId}')/CreateUploadSession\nPOST /formapi/api/{ownerTenant}/users/{owner}/saveResponseLink\nGET  /formapi/api/{responderTenant}/users/{responder}/getResponseLinks\n```\n\nThe normalized model retains raw objects so newly introduced Forms properties\nremain inspectable before this package adds first-class support.\n\n## Limitations\n\n- APIs are private and may change.\n- File upload currently requires the upload question to be visible in the\n  rendered branch.\n- Authentication depends on Microsoft Forms web login behavior.\n- The package is for legitimate form automation. Respect form owners, tenant\n  policies, privacy requirements, and applicable law.\n\n## Development\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md).\n\n```bash\nnpm install\nnpm run type-check\nnpm test\nnpm run format-check\nnpm run spell-check\nnpm run build\n```\n\n## License\n\n[MIT](LICENSE)\n",
  "bytes": 12892,
  "sha": "ec8e1e3d5fce8bb5c4e47328a67b342e133070057afabb184cd6635db18733dc",
  "repo_slug": "maxim-mazurok/msforms-api",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_maxim_mazurok_msforms_api_62fd9247/readme"
}