Add a diagnostic.getServerPort analysis server request.

BUG=
R=brianwilkerson@google.com, scheglov@google.com

Review-Url: https://codereview.chromium.org/2703033002 .
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index e6ad6ea..9756879c 100644
--- a/pkg/analysis_server/doc/api.html
+++ b/pkg/analysis_server/doc/api.html
@@ -108,7 +108,7 @@
 </style></head>
   <body>
     <h1>Analysis Server API Specification</h1>
-    <h1 style="color:#999999">Version 1.17.0</h1>
+    <h1 style="color:#999999">Version 1.18.0</h1>
     <p>
       This document contains a specification of the API provided by the
       analysis server.  The API in this document is currently under
@@ -2405,6 +2405,7 @@
         The diagnostic domain contains server diagnostics APIs.
       </p>
       
+      
     <h3>Requests</h3><dl><dt class="request"><a name="request_diagnostic.getDiagnostics">diagnostic.getDiagnostics</a> (<a href="#request_diagnostic.getDiagnostics">#</a>)</dt><dd><div class="box"><pre>request: {
   "id": String
   "method": "diagnostic.getDiagnostics"
@@ -2420,6 +2421,25 @@
       <h4>returns:</h4><dl><dt class="field"><b>contexts (List&lt;<a href="#type_ContextData">ContextData</a>&gt;)</b></dt><dd>
             
             <p>The list of analysis contexts.</p>
+          </dd></dl></dd><dt class="request"><a name="request_diagnostic.getServerPort">diagnostic.getServerPort</a> (<a href="#request_diagnostic.getServerPort">#</a>)</dt><dd><div class="box"><pre>request: {
+  "id": String
+  "method": "diagnostic.getServerPort"
+}</pre><br><pre>response: {
+  "id": String
+  "error": <span style="color:#999999">optional</span> <a href="#type_RequestError">RequestError</a>
+  "result": {
+    "<b>port</b>": int
+  }
+}</pre></div>
+        <p>
+          Return the port of the diagnostic web server. If the server is not running
+          this call will start the server. If unable to start the diagnostic web server,
+          this call will return an error of <tt>DEBUG_PORT_COULD_NOT_BE_OPENED</tt>.
+        </p>
+        
+      <h4>returns:</h4><dl><dt class="field"><b>port (int)</b></dt><dd>
+            
+            <p>The diagnostic server port.</p>
           </dd></dl></dd></dl>
     
       <h2 class="domain"><a name="types">Types</a></h2>
@@ -3781,6 +3801,11 @@
               not be satisfied because the content of the file changed before
               the requested results could be computed.
             </p>
+          </dd><dt class="value">DEBUG_PORT_COULD_NOT_BE_OPENED</dt><dd>
+            
+            <p>
+              The server was unable to open a port for the diagnostic server.
+            </p>
           </dd><dt class="value">FILE_NOT_ANALYZED</dt><dd>
             
             <p>
@@ -4504,7 +4529,7 @@
       TODO: TBD
     </p>
     <h2 class="domain"><a name="index">Index</a></h2>
-    <h3>Domains</h3><h4>server (<a href="#domain_server">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_server.getVersion">getVersion</a></li><li><a href="#request_server.shutdown">shutdown</a></li><li><a href="#request_server.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_server.connected">connected</a></li><li><a href="#notification_server.error">error</a></li><li><a href="#notification_server.status">status</a></li></ul></div></div><h4>analysis (<a href="#domain_analysis">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_analysis.getErrors">getErrors</a></li><li><a href="#request_analysis.getHover">getHover</a></li><li><a href="#request_analysis.getReachableSources">getReachableSources</a></li><li><a href="#request_analysis.getLibraryDependencies">getLibraryDependencies</a></li><li><a href="#request_analysis.getNavigation">getNavigation</a></li><li><a href="#request_analysis.reanalyze">reanalyze</a></li><li><a href="#request_analysis.setAnalysisRoots">setAnalysisRoots</a></li><li><a href="#request_analysis.setGeneralSubscriptions">setGeneralSubscriptions</a></li><li><a href="#request_analysis.setPriorityFiles">setPriorityFiles</a></li><li><a href="#request_analysis.setSubscriptions">setSubscriptions</a></li><li><a href="#request_analysis.updateContent">updateContent</a></li><li><a href="#request_analysis.updateOptions">updateOptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_analysis.analyzedFiles">analyzedFiles</a></li><li><a href="#notification_analysis.errors">errors</a></li><li><a href="#notification_analysis.flushResults">flushResults</a></li><li><a href="#notification_analysis.folding">folding</a></li><li><a href="#notification_analysis.highlights">highlights</a></li><li><a href="#notification_analysis.implemented">implemented</a></li><li><a href="#notification_analysis.invalidate">invalidate</a></li><li><a href="#notification_analysis.navigation">navigation</a></li><li><a href="#notification_analysis.occurrences">occurrences</a></li><li><a href="#notification_analysis.outline">outline</a></li><li><a href="#notification_analysis.overrides">overrides</a></li></ul></div></div><h4>completion (<a href="#domain_completion">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_completion.getSuggestions">getSuggestions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_completion.results">results</a></li></ul></div></div><h4>search (<a href="#domain_search">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_search.findElementReferences">findElementReferences</a></li><li><a href="#request_search.findMemberDeclarations">findMemberDeclarations</a></li><li><a href="#request_search.findMemberReferences">findMemberReferences</a></li><li><a href="#request_search.findTopLevelDeclarations">findTopLevelDeclarations</a></li><li><a href="#request_search.getTypeHierarchy">getTypeHierarchy</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_search.results">results</a></li></ul></div></div><h4>edit (<a href="#domain_edit">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_edit.format">format</a></li><li><a href="#request_edit.getAssists">getAssists</a></li><li><a href="#request_edit.getAvailableRefactorings">getAvailableRefactorings</a></li><li><a href="#request_edit.getFixes">getFixes</a></li><li><a href="#request_edit.getRefactoring">getRefactoring</a></li><li><a href="#request_edit.sortMembers">sortMembers</a></li><li><a href="#request_edit.organizeDirectives">organizeDirectives</a></li></ul></div><h4>execution (<a href="#domain_execution">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_execution.createContext">createContext</a></li><li><a href="#request_execution.deleteContext">deleteContext</a></li><li><a href="#request_execution.mapUri">mapUri</a></li><li><a href="#request_execution.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_execution.launchData">launchData</a></li></ul></div></div><h4>diagnostic (<a href="#domain_diagnostic">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_diagnostic.getDiagnostics">getDiagnostics</a></li></ul></div><h3>Types (<a href="#types">↑</a>)</h3><div class="subindex"><ul><li><a href="#type_AddContentOverlay">AddContentOverlay</a></li><li><a href="#type_AnalysisError">AnalysisError</a></li><li><a href="#type_AnalysisErrorFixes">AnalysisErrorFixes</a></li><li><a href="#type_AnalysisErrorSeverity">AnalysisErrorSeverity</a></li><li><a href="#type_AnalysisErrorType">AnalysisErrorType</a></li><li><a href="#type_AnalysisOptions">AnalysisOptions</a></li><li><a href="#type_AnalysisService">AnalysisService</a></li><li><a href="#type_AnalysisStatus">AnalysisStatus</a></li><li><a href="#type_ChangeContentOverlay">ChangeContentOverlay</a></li><li><a href="#type_CompletionId">CompletionId</a></li><li><a href="#type_CompletionSuggestion">CompletionSuggestion</a></li><li><a href="#type_CompletionSuggestionKind">CompletionSuggestionKind</a></li><li><a href="#type_ContextData">ContextData</a></li><li><a href="#type_Element">Element</a></li><li><a href="#type_ElementKind">ElementKind</a></li><li><a href="#type_ExecutableFile">ExecutableFile</a></li><li><a href="#type_ExecutableKind">ExecutableKind</a></li><li><a href="#type_ExecutionContextId">ExecutionContextId</a></li><li><a href="#type_ExecutionService">ExecutionService</a></li><li><a href="#type_FileKind">FileKind</a></li><li><a href="#type_FilePath">FilePath</a></li><li><a href="#type_FoldingKind">FoldingKind</a></li><li><a href="#type_FoldingRegion">FoldingRegion</a></li><li><a href="#type_GeneralAnalysisService">GeneralAnalysisService</a></li><li><a href="#type_HighlightRegion">HighlightRegion</a></li><li><a href="#type_HighlightRegionType">HighlightRegionType</a></li><li><a href="#type_HoverInformation">HoverInformation</a></li><li><a href="#type_ImplementedClass">ImplementedClass</a></li><li><a href="#type_ImplementedMember">ImplementedMember</a></li><li><a href="#type_LinkedEditGroup">LinkedEditGroup</a></li><li><a href="#type_LinkedEditSuggestion">LinkedEditSuggestion</a></li><li><a href="#type_LinkedEditSuggestionKind">LinkedEditSuggestionKind</a></li><li><a href="#type_Location">Location</a></li><li><a href="#type_NavigationRegion">NavigationRegion</a></li><li><a href="#type_NavigationTarget">NavigationTarget</a></li><li><a href="#type_Occurrences">Occurrences</a></li><li><a href="#type_Outline">Outline</a></li><li><a href="#type_Override">Override</a></li><li><a href="#type_OverriddenMember">OverriddenMember</a></li><li><a href="#type_Position">Position</a></li><li><a href="#type_PubStatus">PubStatus</a></li><li><a href="#type_RefactoringKind">RefactoringKind</a></li><li><a href="#type_RefactoringMethodParameter">RefactoringMethodParameter</a></li><li><a href="#type_RefactoringFeedback">RefactoringFeedback</a></li><li><a href="#type_RefactoringOptions">RefactoringOptions</a></li><li><a href="#type_RefactoringMethodParameterKind">RefactoringMethodParameterKind</a></li><li><a href="#type_RefactoringProblem">RefactoringProblem</a></li><li><a href="#type_RefactoringProblemSeverity">RefactoringProblemSeverity</a></li><li><a href="#type_RemoveContentOverlay">RemoveContentOverlay</a></li><li><a href="#type_RequestError">RequestError</a></li><li><a href="#type_RequestErrorCode">RequestErrorCode</a></li><li><a href="#type_SearchId">SearchId</a></li><li><a href="#type_SearchResult">SearchResult</a></li><li><a href="#type_SearchResultKind">SearchResultKind</a></li><li><a href="#type_ServerService">ServerService</a></li><li><a href="#type_SourceChange">SourceChange</a></li><li><a href="#type_SourceEdit">SourceEdit</a></li><li><a href="#type_SourceFileEdit">SourceFileEdit</a></li><li><a href="#type_TypeHierarchyItem">TypeHierarchyItem</a></li></ul></div><h3>Refactorings (<a href="#refactorings">↑</a>)</h3><div class="subindex"><ul><li><a href="#refactoring_CONVERT_GETTER_TO_METHOD">CONVERT_GETTER_TO_METHOD</a></li><li><a href="#refactoring_CONVERT_METHOD_TO_GETTER">CONVERT_METHOD_TO_GETTER</a></li><li><a href="#refactoring_EXTRACT_LOCAL_VARIABLE">EXTRACT_LOCAL_VARIABLE</a></li><li><a href="#refactoring_EXTRACT_METHOD">EXTRACT_METHOD</a></li><li><a href="#refactoring_INLINE_LOCAL_VARIABLE">INLINE_LOCAL_VARIABLE</a></li><li><a href="#refactoring_INLINE_METHOD">INLINE_METHOD</a></li><li><a href="#refactoring_MOVE_FILE">MOVE_FILE</a></li><li><a href="#refactoring_RENAME">RENAME</a></li></ul></div>
+    <h3>Domains</h3><h4>server (<a href="#domain_server">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_server.getVersion">getVersion</a></li><li><a href="#request_server.shutdown">shutdown</a></li><li><a href="#request_server.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_server.connected">connected</a></li><li><a href="#notification_server.error">error</a></li><li><a href="#notification_server.status">status</a></li></ul></div></div><h4>analysis (<a href="#domain_analysis">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_analysis.getErrors">getErrors</a></li><li><a href="#request_analysis.getHover">getHover</a></li><li><a href="#request_analysis.getReachableSources">getReachableSources</a></li><li><a href="#request_analysis.getLibraryDependencies">getLibraryDependencies</a></li><li><a href="#request_analysis.getNavigation">getNavigation</a></li><li><a href="#request_analysis.reanalyze">reanalyze</a></li><li><a href="#request_analysis.setAnalysisRoots">setAnalysisRoots</a></li><li><a href="#request_analysis.setGeneralSubscriptions">setGeneralSubscriptions</a></li><li><a href="#request_analysis.setPriorityFiles">setPriorityFiles</a></li><li><a href="#request_analysis.setSubscriptions">setSubscriptions</a></li><li><a href="#request_analysis.updateContent">updateContent</a></li><li><a href="#request_analysis.updateOptions">updateOptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_analysis.analyzedFiles">analyzedFiles</a></li><li><a href="#notification_analysis.errors">errors</a></li><li><a href="#notification_analysis.flushResults">flushResults</a></li><li><a href="#notification_analysis.folding">folding</a></li><li><a href="#notification_analysis.highlights">highlights</a></li><li><a href="#notification_analysis.implemented">implemented</a></li><li><a href="#notification_analysis.invalidate">invalidate</a></li><li><a href="#notification_analysis.navigation">navigation</a></li><li><a href="#notification_analysis.occurrences">occurrences</a></li><li><a href="#notification_analysis.outline">outline</a></li><li><a href="#notification_analysis.overrides">overrides</a></li></ul></div></div><h4>completion (<a href="#domain_completion">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_completion.getSuggestions">getSuggestions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_completion.results">results</a></li></ul></div></div><h4>search (<a href="#domain_search">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_search.findElementReferences">findElementReferences</a></li><li><a href="#request_search.findMemberDeclarations">findMemberDeclarations</a></li><li><a href="#request_search.findMemberReferences">findMemberReferences</a></li><li><a href="#request_search.findTopLevelDeclarations">findTopLevelDeclarations</a></li><li><a href="#request_search.getTypeHierarchy">getTypeHierarchy</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_search.results">results</a></li></ul></div></div><h4>edit (<a href="#domain_edit">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_edit.format">format</a></li><li><a href="#request_edit.getAssists">getAssists</a></li><li><a href="#request_edit.getAvailableRefactorings">getAvailableRefactorings</a></li><li><a href="#request_edit.getFixes">getFixes</a></li><li><a href="#request_edit.getRefactoring">getRefactoring</a></li><li><a href="#request_edit.sortMembers">sortMembers</a></li><li><a href="#request_edit.organizeDirectives">organizeDirectives</a></li></ul></div><h4>execution (<a href="#domain_execution">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_execution.createContext">createContext</a></li><li><a href="#request_execution.deleteContext">deleteContext</a></li><li><a href="#request_execution.mapUri">mapUri</a></li><li><a href="#request_execution.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_execution.launchData">launchData</a></li></ul></div></div><h4>diagnostic (<a href="#domain_diagnostic">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_diagnostic.getDiagnostics">getDiagnostics</a></li><li><a href="#request_diagnostic.getServerPort">getServerPort</a></li></ul></div><h3>Types (<a href="#types">↑</a>)</h3><div class="subindex"><ul><li><a href="#type_AddContentOverlay">AddContentOverlay</a></li><li><a href="#type_AnalysisError">AnalysisError</a></li><li><a href="#type_AnalysisErrorFixes">AnalysisErrorFixes</a></li><li><a href="#type_AnalysisErrorSeverity">AnalysisErrorSeverity</a></li><li><a href="#type_AnalysisErrorType">AnalysisErrorType</a></li><li><a href="#type_AnalysisOptions">AnalysisOptions</a></li><li><a href="#type_AnalysisService">AnalysisService</a></li><li><a href="#type_AnalysisStatus">AnalysisStatus</a></li><li><a href="#type_ChangeContentOverlay">ChangeContentOverlay</a></li><li><a href="#type_CompletionId">CompletionId</a></li><li><a href="#type_CompletionSuggestion">CompletionSuggestion</a></li><li><a href="#type_CompletionSuggestionKind">CompletionSuggestionKind</a></li><li><a href="#type_ContextData">ContextData</a></li><li><a href="#type_Element">Element</a></li><li><a href="#type_ElementKind">ElementKind</a></li><li><a href="#type_ExecutableFile">ExecutableFile</a></li><li><a href="#type_ExecutableKind">ExecutableKind</a></li><li><a href="#type_ExecutionContextId">ExecutionContextId</a></li><li><a href="#type_ExecutionService">ExecutionService</a></li><li><a href="#type_FileKind">FileKind</a></li><li><a href="#type_FilePath">FilePath</a></li><li><a href="#type_FoldingKind">FoldingKind</a></li><li><a href="#type_FoldingRegion">FoldingRegion</a></li><li><a href="#type_GeneralAnalysisService">GeneralAnalysisService</a></li><li><a href="#type_HighlightRegion">HighlightRegion</a></li><li><a href="#type_HighlightRegionType">HighlightRegionType</a></li><li><a href="#type_HoverInformation">HoverInformation</a></li><li><a href="#type_ImplementedClass">ImplementedClass</a></li><li><a href="#type_ImplementedMember">ImplementedMember</a></li><li><a href="#type_LinkedEditGroup">LinkedEditGroup</a></li><li><a href="#type_LinkedEditSuggestion">LinkedEditSuggestion</a></li><li><a href="#type_LinkedEditSuggestionKind">LinkedEditSuggestionKind</a></li><li><a href="#type_Location">Location</a></li><li><a href="#type_NavigationRegion">NavigationRegion</a></li><li><a href="#type_NavigationTarget">NavigationTarget</a></li><li><a href="#type_Occurrences">Occurrences</a></li><li><a href="#type_Outline">Outline</a></li><li><a href="#type_Override">Override</a></li><li><a href="#type_OverriddenMember">OverriddenMember</a></li><li><a href="#type_Position">Position</a></li><li><a href="#type_PubStatus">PubStatus</a></li><li><a href="#type_RefactoringKind">RefactoringKind</a></li><li><a href="#type_RefactoringMethodParameter">RefactoringMethodParameter</a></li><li><a href="#type_RefactoringFeedback">RefactoringFeedback</a></li><li><a href="#type_RefactoringOptions">RefactoringOptions</a></li><li><a href="#type_RefactoringMethodParameterKind">RefactoringMethodParameterKind</a></li><li><a href="#type_RefactoringProblem">RefactoringProblem</a></li><li><a href="#type_RefactoringProblemSeverity">RefactoringProblemSeverity</a></li><li><a href="#type_RemoveContentOverlay">RemoveContentOverlay</a></li><li><a href="#type_RequestError">RequestError</a></li><li><a href="#type_RequestErrorCode">RequestErrorCode</a></li><li><a href="#type_SearchId">SearchId</a></li><li><a href="#type_SearchResult">SearchResult</a></li><li><a href="#type_SearchResultKind">SearchResultKind</a></li><li><a href="#type_ServerService">ServerService</a></li><li><a href="#type_SourceChange">SourceChange</a></li><li><a href="#type_SourceEdit">SourceEdit</a></li><li><a href="#type_SourceFileEdit">SourceFileEdit</a></li><li><a href="#type_TypeHierarchyItem">TypeHierarchyItem</a></li></ul></div><h3>Refactorings (<a href="#refactorings">↑</a>)</h3><div class="subindex"><ul><li><a href="#refactoring_CONVERT_GETTER_TO_METHOD">CONVERT_GETTER_TO_METHOD</a></li><li><a href="#refactoring_CONVERT_METHOD_TO_GETTER">CONVERT_METHOD_TO_GETTER</a></li><li><a href="#refactoring_EXTRACT_LOCAL_VARIABLE">EXTRACT_LOCAL_VARIABLE</a></li><li><a href="#refactoring_EXTRACT_METHOD">EXTRACT_METHOD</a></li><li><a href="#refactoring_INLINE_LOCAL_VARIABLE">INLINE_LOCAL_VARIABLE</a></li><li><a href="#refactoring_INLINE_METHOD">INLINE_METHOD</a></li><li><a href="#refactoring_MOVE_FILE">MOVE_FILE</a></li><li><a href="#refactoring_RENAME">RENAME</a></li></ul></div>
   
 
 </body></html>
\ No newline at end of file
diff --git a/pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart b/pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart
index 9a11d6a..59b76b0 100644
--- a/pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart
+++ b/pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart
@@ -7759,6 +7759,109 @@
     return JenkinsSmiHash.finish(hash);
   }
 }
+/**
+ * diagnostic.getServerPort params
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class DiagnosticGetServerPortParams {
+  Request toRequest(String id) {
+    return new Request(id, "diagnostic.getServerPort", null);
+  }
+
+  @override
+  bool operator==(other) {
+    if (other is DiagnosticGetServerPortParams) {
+      return true;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    return 367508704;
+  }
+}
+
+/**
+ * diagnostic.getServerPort result
+ *
+ * {
+ *   "port": int
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class DiagnosticGetServerPortResult implements HasToJson {
+  int _port;
+
+  /**
+   * The diagnostic server port.
+   */
+  int get port => _port;
+
+  /**
+   * The diagnostic server port.
+   */
+  void set port(int value) {
+    assert(value != null);
+    this._port = value;
+  }
+
+  DiagnosticGetServerPortResult(int port) {
+    this.port = port;
+  }
+
+  factory DiagnosticGetServerPortResult.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      int port;
+      if (json.containsKey("port")) {
+        port = jsonDecoder.decodeInt(jsonPath + ".port", json["port"]);
+      } else {
+        throw jsonDecoder.missingKey(jsonPath, "port");
+      }
+      return new DiagnosticGetServerPortResult(port);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "diagnostic.getServerPort result", json);
+    }
+  }
+
+  factory DiagnosticGetServerPortResult.fromResponse(Response response) {
+    return new DiagnosticGetServerPortResult.fromJson(
+        new ResponseDecoder(REQUEST_ID_REFACTORING_KINDS.remove(response.id)), "result", response._result);
+  }
+
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    result["port"] = port;
+    return result;
+  }
+
+  Response toResponse(String id) {
+    return new Response(id, result: toJson());
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
+  @override
+  bool operator==(other) {
+    if (other is DiagnosticGetServerPortResult) {
+      return port == other.port;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode {
+    int hash = 0;
+    hash = JenkinsSmiHash.combine(hash, port.hashCode);
+    return JenkinsSmiHash.finish(hash);
+  }
+}
 
 /**
  * AddContentOverlay
@@ -14204,6 +14307,7 @@
  *
  * enum {
  *   CONTENT_MODIFIED
+ *   DEBUG_PORT_COULD_NOT_BE_OPENED
  *   FILE_NOT_ANALYZED
  *   FORMAT_INVALID_FILE
  *   FORMAT_WITH_ERRORS
@@ -14240,6 +14344,11 @@
   static const RequestErrorCode CONTENT_MODIFIED = const RequestErrorCode._("CONTENT_MODIFIED");
 
   /**
+   * The server was unable to open a port for the diagnostic server.
+   */
+  static const RequestErrorCode DEBUG_PORT_COULD_NOT_BE_OPENED = const RequestErrorCode._("DEBUG_PORT_COULD_NOT_BE_OPENED");
+
+  /**
    * A request specified a FilePath which does not match a file in an analysis
    * root, or the requested operation is not available for the file.
    */
@@ -14386,7 +14495,7 @@
   /**
    * A list containing all of the enum values that are defined.
    */
-  static const List<RequestErrorCode> VALUES = const <RequestErrorCode>[CONTENT_MODIFIED, FILE_NOT_ANALYZED, FORMAT_INVALID_FILE, FORMAT_WITH_ERRORS, GET_ERRORS_INVALID_FILE, GET_NAVIGATION_INVALID_FILE, GET_REACHABLE_SOURCES_INVALID_FILE, INVALID_ANALYSIS_ROOT, INVALID_EXECUTION_CONTEXT, INVALID_FILE_PATH_FORMAT, INVALID_OVERLAY_CHANGE, INVALID_PARAMETER, INVALID_REQUEST, NO_INDEX_GENERATED, ORGANIZE_DIRECTIVES_ERROR, REFACTORING_REQUEST_CANCELLED, SERVER_ALREADY_STARTED, SERVER_ERROR, SORT_MEMBERS_INVALID_FILE, SORT_MEMBERS_PARSE_ERRORS, UNANALYZED_PRIORITY_FILES, UNKNOWN_REQUEST, UNKNOWN_SOURCE, UNSUPPORTED_FEATURE];
+  static const List<RequestErrorCode> VALUES = const <RequestErrorCode>[CONTENT_MODIFIED, DEBUG_PORT_COULD_NOT_BE_OPENED, FILE_NOT_ANALYZED, FORMAT_INVALID_FILE, FORMAT_WITH_ERRORS, GET_ERRORS_INVALID_FILE, GET_NAVIGATION_INVALID_FILE, GET_REACHABLE_SOURCES_INVALID_FILE, INVALID_ANALYSIS_ROOT, INVALID_EXECUTION_CONTEXT, INVALID_FILE_PATH_FORMAT, INVALID_OVERLAY_CHANGE, INVALID_PARAMETER, INVALID_REQUEST, NO_INDEX_GENERATED, ORGANIZE_DIRECTIVES_ERROR, REFACTORING_REQUEST_CANCELLED, SERVER_ALREADY_STARTED, SERVER_ERROR, SORT_MEMBERS_INVALID_FILE, SORT_MEMBERS_PARSE_ERRORS, UNANALYZED_PRIORITY_FILES, UNKNOWN_REQUEST, UNKNOWN_SOURCE, UNSUPPORTED_FEATURE];
 
   final String name;
 
@@ -14396,6 +14505,8 @@
     switch (name) {
       case "CONTENT_MODIFIED":
         return CONTENT_MODIFIED;
+      case "DEBUG_PORT_COULD_NOT_BE_OPENED":
+        return DEBUG_PORT_COULD_NOT_BE_OPENED;
       case "FILE_NOT_ANALYZED":
         return FILE_NOT_ANALYZED;
       case "FORMAT_INVALID_FILE":
diff --git a/pkg/analysis_server/lib/plugin/protocol/protocol.dart b/pkg/analysis_server/lib/plugin/protocol/protocol.dart
index 49e19c1..ea425cf 100644
--- a/pkg/analysis_server/lib/plugin/protocol/protocol.dart
+++ b/pkg/analysis_server/lib/plugin/protocol/protocol.dart
@@ -339,6 +339,14 @@
       : _result = result;
 
   /**
+   * Create and return the `DEBUG_PORT_COULD_NOT_BE_OPENED` error response.
+   */
+  Response.debugPortCouldNotBeOpened(Request request, dynamic error)
+      : this(request.id,
+      error: new RequestError(
+          RequestErrorCode.DEBUG_PORT_COULD_NOT_BE_OPENED, '$error'));
+
+  /**
    * Initialize a newly created instance to represent the FILE_NOT_ANALYZED
    * error condition.
    */
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index d8703ce..c46ca60 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -20,6 +20,7 @@
 import 'package:analysis_server/src/operation/operation_analysis.dart';
 import 'package:analysis_server/src/operation/operation_queue.dart';
 import 'package:analysis_server/src/plugin/server_plugin.dart';
+import 'package:analysis_server/src/server/diagnostic_server.dart';
 import 'package:analysis_server/src/services/correction/namespace.dart';
 import 'package:analysis_server/src/services/index/index.dart';
 import 'package:analysis_server/src/services/search/search_engine.dart';
@@ -91,7 +92,7 @@
    * The version of the analysis server. The value should be replaced
    * automatically during the build.
    */
-  static final String VERSION = '1.17.0';
+  static final String VERSION = '1.18.0';
 
   /**
    * The number of milliseconds to perform operations before inserting
@@ -329,6 +330,13 @@
   final Set<String> priorityFiles = new Set<String>();
 
   /**
+   * The DiagnosticServer for this AnalysisServer. If available, it can be used
+   * to start an http diagnostics server or return the port for an existing
+   * server.
+   */
+  DiagnosticServer diagnosticServer;
+
+  /**
    * Initialize a newly created server to receive requests from and send
    * responses to the given [channel].
    *
@@ -346,7 +354,8 @@
       this.options,
       this.sdkManager,
       this.instrumentationService,
-      {ResolverProvider fileResolverProvider: null,
+      {this.diagnosticServer,
+      ResolverProvider fileResolverProvider: null,
       ResolverProvider packageResolverProvider: null,
       bool useSingleContextManager: false,
       this.rethrowExceptions: true}) {
diff --git a/pkg/analysis_server/lib/src/constants.dart b/pkg/analysis_server/lib/src/constants.dart
index 5054f7b..519bbfe 100644
--- a/pkg/analysis_server/lib/src/constants.dart
+++ b/pkg/analysis_server/lib/src/constants.dart
@@ -97,6 +97,12 @@
 const String EDITS = 'edits';
 
 //
+// Diagnostics methods
+//
+const String DIAGNOSTIC_GET_DIAGNOSTICS = 'diagnostic.getDiagnostics';
+const String DIAGNOSTIC_GET_SERVER_PORT = 'diagnostic.getServerPort';
+
+//
 // Analysis option names
 //
 const String ELEMENT = 'element'; // boolean
diff --git a/pkg/analysis_server/lib/src/domain_diagnostic.dart b/pkg/analysis_server/lib/src/domain_diagnostic.dart
index d91aacf..738f129 100644
--- a/pkg/analysis_server/lib/src/domain_diagnostic.dart
+++ b/pkg/analysis_server/lib/src/domain_diagnostic.dart
@@ -4,11 +4,13 @@
 
 library analysis_server.src.domain_diagnostic;
 
+import 'dart:async';
 import 'dart:collection';
 import 'dart:core';
 
 import 'package:analysis_server/plugin/protocol/protocol.dart';
 import 'package:analysis_server/src/analysis_server.dart';
+import 'package:analysis_server/src/constants.dart';
 import 'package:analyzer/src/context/cache.dart';
 import 'package:analyzer/src/context/context.dart';
 import 'package:analyzer/src/dart/analysis/driver.dart' as nd;
@@ -27,9 +29,6 @@
 /// Instances of the class [DiagnosticDomainHandler] implement a
 /// [RequestHandler] that handles requests in the `diagnostic` domain.
 class DiagnosticDomainHandler implements RequestHandler {
-  /// The name of the request used to get diagnostic information.
-  static const String DIAGNOSTICS = 'diagnostic.getDiagnostics';
-
   /// The analysis server that is using this handler to process requests.
   final AnalysisServer server;
 
@@ -37,7 +36,7 @@
   /// [server].
   DiagnosticDomainHandler(this.server);
 
-  /// Answer the `diagnostic.diagnostics` request.
+  /// Answer the `diagnostic.getDiagnostics` request.
   Response computeDiagnostics(Request request) {
     List<ContextData> contexts = <ContextData>[];
     if (server.options.enableNewAnalysisDriver) {
@@ -101,12 +100,28 @@
   Response handleRequest(Request request) {
     try {
       String requestName = request.method;
-      if (requestName == DIAGNOSTICS) {
+      if (requestName == DIAGNOSTIC_GET_DIAGNOSTICS) {
         return computeDiagnostics(request);
+      } else if (requestName == DIAGNOSTIC_GET_SERVER_PORT) {
+        handleGetServerPort(request);
+        return Response.DELAYED_RESPONSE;
       }
     } on RequestFailure catch (exception) {
       return exception.response;
     }
     return null;
   }
+
+  /// Answer the `diagnostic.getServerPort` request.
+  Future handleGetServerPort(Request request) async {
+    try {
+      // Open a port (or return the existing one).
+      int port = await server.diagnosticServer.getServerPort();
+      server.sendResponse(
+          new DiagnosticGetServerPortResult(port).toResponse(request.id));
+    } catch (error) {
+      server
+          .sendResponse(new Response.debugPortCouldNotBeOpened(request, error));
+    }
+  }
 }
diff --git a/pkg/analysis_server/lib/src/server/diagnostic_server.dart b/pkg/analysis_server/lib/src/server/diagnostic_server.dart
new file mode 100644
index 0000000..b147a43
--- /dev/null
+++ b/pkg/analysis_server/lib/src/server/diagnostic_server.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+/**
+ * A handle to start, and return the current port of, a diagnostic server.
+ */
+abstract class DiagnosticServer {
+  /**
+   * Return the port of the diagnostic web server. If the server is not running
+   * this call will start the server.
+   */
+  Future<int> getServerPort();
+}
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index 44e7c19..bc6baf2 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -11,6 +11,7 @@
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/plugin/server_plugin.dart';
 import 'package:analysis_server/src/provisional/completion/dart/completion_plugin.dart';
+import 'package:analysis_server/src/server/diagnostic_server.dart';
 import 'package:analysis_server/src/server/http_server.dart';
 import 'package:analysis_server/src/server/stdio_server.dart';
 import 'package:analysis_server/src/socket_server.dart';
@@ -371,9 +372,9 @@
     int port;
     bool serve_http = false;
     if (results[PORT_OPTION] != null) {
-      serve_http = true;
       try {
         port = int.parse(results[PORT_OPTION]);
+        serve_http = true;
       } on FormatException {
         print('Invalid port number: ${results[PORT_OPTION]}');
         print('');
@@ -444,11 +445,18 @@
               [instrumentationServer, fileBasedServer])
           : fileBasedServer;
     }
-    InstrumentationService service =
+    InstrumentationService instrumentationService =
         new InstrumentationService(instrumentationServer);
-    service.logVersion(_readUuid(service), results[CLIENT_ID],
-        results[CLIENT_VERSION], AnalysisServer.VERSION, defaultSdk.sdkVersion);
-    AnalysisEngine.instance.instrumentationService = service;
+    instrumentationService.logVersion(
+        _readUuid(instrumentationService),
+        results[CLIENT_ID],
+        results[CLIENT_VERSION],
+        AnalysisServer.VERSION,
+        defaultSdk.sdkVersion);
+    AnalysisEngine.instance.instrumentationService = instrumentationService;
+
+    _DiagnosticServerImpl diagnosticServer = new _DiagnosticServerImpl();
+
     //
     // Create the sockets and start listening for requests.
     //
@@ -456,7 +464,8 @@
         analysisServerOptions,
         new DartSdkManager(defaultSdkPath, useSummaries),
         defaultSdk,
-        service,
+        instrumentationService,
+        diagnosticServer,
         serverPlugin,
         fileResolverProvider,
         packageResolverProvider,
@@ -465,16 +474,17 @@
     stdioServer = new StdioAnalysisServer(socketServer);
     socketServer.userDefinedPlugins = _userDefinedPlugins;
 
+    diagnosticServer.httpServer = httpServer;
     if (serve_http) {
-      httpServer.serveHttp(port);
+      diagnosticServer.startOnPort(port);
     }
 
-    _captureExceptions(service, () {
+    _captureExceptions(instrumentationService, () {
       stdioServer.serveStdio().then((_) async {
         if (serve_http) {
           httpServer.close();
         }
-        await service.shutdown();
+        await instrumentationService.shutdown();
         exit(0);
       });
     },
@@ -651,3 +661,19 @@
     }
   }
 }
+
+/**
+ * Implements the [DiagnosticServer] class by wrapping an [HttpAnalysisServer].
+ */
+class _DiagnosticServerImpl extends DiagnosticServer {
+  HttpAnalysisServer httpServer;
+
+  _DiagnosticServerImpl();
+
+  Future startOnPort(int port) {
+    return httpServer.serveHttp(port);
+  }
+
+  @override
+  Future<int> getServerPort() => httpServer.serveHttp();
+}
diff --git a/pkg/analysis_server/lib/src/server/http_server.dart b/pkg/analysis_server/lib/src/server/http_server.dart
index 85c3557..48057fd 100644
--- a/pkg/analysis_server/lib/src/server/http_server.dart
+++ b/pkg/analysis_server/lib/src/server/http_server.dart
@@ -14,8 +14,10 @@
 
 /**
  * Instances of the class [HttpServer] implement a simple HTTP server. The
- * primary responsibility of this server is to listen for an UPGRADE request and
- * to start an analysis server.
+ * server:
+ *
+ * - listens for an UPGRADE request in order to start an analysis server
+ * - serves diagnostic information as html pages
  */
 class HttpAnalysisServer {
   /**
@@ -49,6 +51,11 @@
    */
   HttpAnalysisServer(this.socketServer);
 
+  /**
+   * Return the port this server is bound to.
+   */
+  Future<int> get boundPort async => (await _server)?.port;
+
   void close() {
     _server.then((HttpServer server) {
       server.close();
@@ -69,9 +76,20 @@
   /**
    * Begin serving HTTP requests over the given port.
    */
-  void serveHttp(int port) {
-    _server = HttpServer.bind(InternetAddress.LOOPBACK_IP_V4, port);
-    _server.then(_handleServer).catchError((_) {/* Ignore errors. */});
+  Future<int> serveHttp([int initialPort]) async {
+    if (_server != null) {
+      return boundPort;
+    }
+
+    try {
+      _server =
+          HttpServer.bind(InternetAddress.LOOPBACK_IP_V4, initialPort ?? 0);
+      HttpServer server = await _server;
+      _handleServer(server);
+      return server.port;
+    } catch (ignore) {
+      return null;
+    }
   }
 
   /**
@@ -111,6 +129,8 @@
    * running an analysis server on a [WebSocket]-based communication channel.
    */
   void _handleWebSocket(WebSocket socket) {
+    // TODO(devoncarew): This serves the analysis server over a websocket
+    // connection for historical reasons (and should probably be removed).
     socketServer.createAnalysisServer(new WebSocketServerChannel(
         socket, socketServer.instrumentationService));
   }
diff --git a/pkg/analysis_server/lib/src/socket_server.dart b/pkg/analysis_server/lib/src/socket_server.dart
index 887e1b7..183b11d 100644
--- a/pkg/analysis_server/lib/src/socket_server.dart
+++ b/pkg/analysis_server/lib/src/socket_server.dart
@@ -8,6 +8,7 @@
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/channel/channel.dart';
 import 'package:analysis_server/src/plugin/server_plugin.dart';
+import 'package:analysis_server/src/server/diagnostic_server.dart';
 import 'package:analysis_server/src/services/index/index.dart';
 import 'package:analyzer/file_system/physical_file_system.dart';
 import 'package:analyzer/instrumentation/instrumentation.dart';
@@ -32,6 +33,7 @@
 
   final DartSdk defaultSdk;
   final InstrumentationService instrumentationService;
+  final DiagnosticServer diagnosticServer;
   final ServerPlugin serverPlugin;
   final ResolverProvider fileResolverProvider;
   final ResolverProvider packageResolverProvider;
@@ -53,6 +55,7 @@
       this.sdkManager,
       this.defaultSdk,
       this.instrumentationService,
+      this.diagnosticServer,
       this.serverPlugin,
       this.fileResolverProvider,
       this.packageResolverProvider,
@@ -98,6 +101,7 @@
         analysisServerOptions,
         sdkManager,
         instrumentationService,
+        diagnosticServer: diagnosticServer,
         fileResolverProvider: fileResolverProvider,
         packageResolverProvider: packageResolverProvider,
         useSingleContextManager: useSingleContextManager,
diff --git a/pkg/analysis_server/test/integration/coverage.md b/pkg/analysis_server/test/integration/coverage.md
index 244bb11..9dd2ed2 100644
--- a/pkg/analysis_server/test/integration/coverage.md
+++ b/pkg/analysis_server/test/integration/coverage.md
@@ -51,3 +51,4 @@
 
 ## diagnostic domain
 - [x] diagnostic.getDiagnostics
+- [x] diagnostic.getServerPort
diff --git a/pkg/analysis_server/test/integration/diagnostic/get_server_port_test.dart b/pkg/analysis_server/test/integration/diagnostic/get_server_port_test.dart
new file mode 100644
index 0000000..176e483
--- /dev/null
+++ b/pkg/analysis_server/test/integration/diagnostic/get_server_port_test.dart
@@ -0,0 +1,40 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:analysis_server/plugin/protocol/protocol.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../integration_tests.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(GetServerPortTest);
+  });
+}
+
+@reflectiveTest
+class GetServerPortTest extends AbstractAnalysisServerIntegrationTest {
+  test_connect() async {
+    standardAnalysisSetup();
+
+    DiagnosticGetServerPortResult result = await sendDiagnosticGetServerPort();
+    expect(result.port, isNotNull);
+    expect(result.port, isNonZero);
+
+    // Connect to the server and verify that it's serving the status page.
+    HttpClient client = new HttpClient();
+    HttpClientRequest request = await client
+        .getUrl(Uri.parse('http://localhost:${result.port}/status'));
+    HttpClientResponse response = await request.close();
+    String responseBody = await UTF8.decodeStream(response);
+    expect(responseBody, contains('<title>Analysis Server</title>'));
+  }
+
+  @override
+  bool get enableNewAnalysisDriver => true;
+}
diff --git a/pkg/analysis_server/test/integration/diagnostic/test_all.dart b/pkg/analysis_server/test/integration/diagnostic/test_all.dart
index 99f1229..4e45dea 100644
--- a/pkg/analysis_server/test/integration/diagnostic/test_all.dart
+++ b/pkg/analysis_server/test/integration/diagnostic/test_all.dart
@@ -5,9 +5,11 @@
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import 'get_diagnostics_test.dart' as get_diagnostics_test;
+import 'get_server_port_test.dart' as get_server_port_test;
 
 main() {
   defineReflectiveSuite(() {
     get_diagnostics_test.main();
+    get_server_port_test.main();
   }, name: 'diagnostics');
 }
diff --git a/pkg/analysis_server/test/integration/integration_test_methods.dart b/pkg/analysis_server/test/integration/integration_test_methods.dart
index 4bad372..14251bb 100644
--- a/pkg/analysis_server/test/integration/integration_test_methods.dart
+++ b/pkg/analysis_server/test/integration/integration_test_methods.dart
@@ -1630,6 +1630,23 @@
   }
 
   /**
+   * Return the port of the diagnostic web server. If the server is not running
+   * this call will start the server. If unable to start the diagnostic web
+   * server, this call will return an error of DEBUG_PORT_COULD_NOT_BE_OPENED.
+   *
+   * Returns
+   *
+   * port (int)
+   *
+   *   The diagnostic server port.
+   */
+  Future<DiagnosticGetServerPortResult> sendDiagnosticGetServerPort() async {
+    var result = await server.send("diagnostic.getServerPort", null);
+    ResponseDecoder decoder = new ResponseDecoder(null);
+    return new DiagnosticGetServerPortResult.fromJson(decoder, 'result', result);
+  }
+
+  /**
    * Initialize the fields in InttestMixin, and ensure that notifications will
    * be handled.
    */
diff --git a/pkg/analysis_server/test/integration/protocol_matchers.dart b/pkg/analysis_server/test/integration/protocol_matchers.dart
index 7f2f3ab..58a53bd 100644
--- a/pkg/analysis_server/test/integration/protocol_matchers.dart
+++ b/pkg/analysis_server/test/integration/protocol_matchers.dart
@@ -1053,6 +1053,23 @@
   }));
 
 /**
+ * diagnostic.getServerPort params
+ */
+final Matcher isDiagnosticGetServerPortParams = isNull;
+
+/**
+ * diagnostic.getServerPort result
+ *
+ * {
+ *   "port": int
+ * }
+ */
+final Matcher isDiagnosticGetServerPortResult = new LazyMatcher(() => new MatchesJsonObject(
+  "diagnostic.getServerPort result", {
+    "port": isInt
+  }));
+
+/**
  * AddContentOverlay
  *
  * {
@@ -2103,6 +2120,7 @@
  *
  * enum {
  *   CONTENT_MODIFIED
+ *   DEBUG_PORT_COULD_NOT_BE_OPENED
  *   FILE_NOT_ANALYZED
  *   FORMAT_INVALID_FILE
  *   FORMAT_WITH_ERRORS
@@ -2130,6 +2148,7 @@
  */
 final Matcher isRequestErrorCode = new MatchesEnum("RequestErrorCode", [
   "CONTENT_MODIFIED",
+  "DEBUG_PORT_COULD_NOT_BE_OPENED",
   "FILE_NOT_ANALYZED",
   "FORMAT_INVALID_FILE",
   "FORMAT_WITH_ERRORS",
diff --git a/pkg/analysis_server/test/socket_server_test.dart b/pkg/analysis_server/test/socket_server_test.dart
index a6ea8b1..c3caaed 100644
--- a/pkg/analysis_server/test/socket_server_test.dart
+++ b/pkg/analysis_server/test/socket_server_test.dart
@@ -119,6 +119,7 @@
         new FolderBasedDartSdk(resourceProvider,
             FolderBasedDartSdk.defaultSdkDirectory(resourceProvider)),
         InstrumentationService.NULL_SERVICE,
+        null,
         serverPlugin,
         null,
         null,
diff --git a/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java b/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
index 8fb6d55..99e5ac0 100644
--- a/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
+++ b/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
@@ -298,6 +298,15 @@
   public void diagnostic_getDiagnostics(GetDiagnosticsConsumer consumer);
 
   /**
+   * {@code diagnostic.getServerPort}
+   *
+   * Return the port of the diagnostic web server. If the server is not running this call will start
+   * the server. If unable to start the diagnostic web server, this call will return an error of
+   * DEBUG_PORT_COULD_NOT_BE_OPENED.
+   */
+  public void diagnostic_getServerPort(GetServerPortConsumer consumer);
+
+  /**
    * {@code edit.format}
    *
    * Format the contents of a single file. The currently selected region of text is passed in so that
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java b/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
index 346bf63..37c06b5 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
@@ -30,6 +30,11 @@
   public static final String CONTENT_MODIFIED = "CONTENT_MODIFIED";
 
   /**
+   * The server was unable to open a port for the diagnostic server.
+   */
+  public static final String DEBUG_PORT_COULD_NOT_BE_OPENED = "DEBUG_PORT_COULD_NOT_BE_OPENED";
+
+  /**
    * A request specified a FilePath which does not match a file in an analysis root, or the requested
    * operation is not available for the file.
    */
diff --git a/pkg/analysis_server/tool/spec/spec_input.html b/pkg/analysis_server/tool/spec/spec_input.html
index d9213e2..2297a33 100644
--- a/pkg/analysis_server/tool/spec/spec_input.html
+++ b/pkg/analysis_server/tool/spec/spec_input.html
@@ -6,7 +6,7 @@
   </head>
   <body>
     <h1>Analysis Server API Specification</h1>
-    <h1 style="color:#999999">Version <version>1.17.0</version></h1>
+    <h1 style="color:#999999">Version <version>1.18.0</version></h1>
     <p>
       This document contains a specification of the API provided by the
       analysis server.  The API in this document is currently under
@@ -2049,6 +2049,19 @@
           </field>
         </result>
       </request>
+      <request method="getServerPort">
+        <p>
+          Return the port of the diagnostic web server. If the server is not running
+          this call will start the server. If unable to start the diagnostic web server,
+          this call will return an error of <tt>DEBUG_PORT_COULD_NOT_BE_OPENED</tt>.
+        </p>
+        <result>
+          <field name="port">
+            <ref>int</ref>
+            <p>The diagnostic server port.</p>
+          </field>
+        </result>
+      </request>
     </domain>
     <types>
       <h2 class="domain"><a name="types">Types</a></h2>
@@ -3731,6 +3744,12 @@
             </p>
           </value>
           <value>
+            <code>DEBUG_PORT_COULD_NOT_BE_OPENED</code>
+            <p>
+              The server was unable to open a port for the diagnostic server.
+            </p>
+          </value>
+          <value>
             <code>FILE_NOT_ANALYZED</code>
             <p>
               A request specified a FilePath which does not match a file in